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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveSchema } from "./helpers.ts";
|
|
1
|
+
import { isNullable, resolveSchema } from "./helpers.ts";
|
|
2
2
|
import type { SchemaLike, SpecValue } from "./helpers.ts";
|
|
3
3
|
import type { ValidationSchema } from "./request.ts";
|
|
4
4
|
|
|
@@ -50,6 +50,14 @@ export const inputValue = (value: SpecValue): string => {
|
|
|
50
50
|
/** Recursion limit for pruned validation schemas — deep enough for real specs. */
|
|
51
51
|
const MAX_SCHEMA_DEPTH = 6;
|
|
52
52
|
|
|
53
|
+
/** Whether a property is `readOnly`, on the property or the schema it refs. */
|
|
54
|
+
const isReadOnly = (
|
|
55
|
+
property: SchemaLike | undefined,
|
|
56
|
+
schemas: Record<string, SchemaLike>
|
|
57
|
+
): boolean =>
|
|
58
|
+
property?.readOnly === true ||
|
|
59
|
+
resolveSchema(schemas, property).readOnly === true;
|
|
60
|
+
|
|
53
61
|
/**
|
|
54
62
|
* Prune a spec schema into the tiny subset `validate-json.ts` understands:
|
|
55
63
|
* `$ref`s resolved inline, cycles cut (the visited set is copied per branch so
|
|
@@ -74,15 +82,26 @@ const pruneSchema = (
|
|
|
74
82
|
}
|
|
75
83
|
const resolved = resolveSchema(schemas, schema);
|
|
76
84
|
const out: ValidationSchema = {};
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
// Only a single declared type is checked: a 3.1 type array like
|
|
86
|
+
// `["string", "integer"]` accepts either, which one `type` can't say.
|
|
87
|
+
const types = declaredTypes(resolved.type);
|
|
88
|
+
if (types.length === 1) {
|
|
89
|
+
[out.type] = types;
|
|
90
|
+
}
|
|
91
|
+
if (isNullable(resolved)) {
|
|
92
|
+
out.nullable = true;
|
|
80
93
|
}
|
|
81
94
|
if (resolved.enum) {
|
|
82
95
|
out.enum = resolved.enum;
|
|
83
96
|
}
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
// A `readOnly` property's `required` binds responses only: the server
|
|
98
|
+
// generates it, so a request body — which the prefilled example already
|
|
99
|
+
// leaves it out of — must not be told it is missing.
|
|
100
|
+
const required = (resolved.required ?? []).filter(
|
|
101
|
+
(name) => !isReadOnly(resolved.properties?.[name], schemas)
|
|
102
|
+
);
|
|
103
|
+
if (required.length > 0) {
|
|
104
|
+
out.required = required;
|
|
86
105
|
}
|
|
87
106
|
if (resolved.properties) {
|
|
88
107
|
const properties: Record<string, ValidationSchema> = {};
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultExplode,
|
|
3
|
+
defaultStyle,
|
|
4
|
+
isJsonObject,
|
|
5
|
+
memberText,
|
|
6
|
+
parseStyledValue,
|
|
7
|
+
queryPairs,
|
|
8
|
+
styledValue,
|
|
9
|
+
templateValue,
|
|
10
|
+
} from "./param-style.ts";
|
|
11
|
+
import type { JsonValue } from "./param-style.ts";
|
|
1
12
|
import type { RequestSample } from "./snippets.ts";
|
|
2
13
|
|
|
3
14
|
/**
|
|
@@ -10,7 +21,18 @@ import type { RequestSample } from "./snippets.ts";
|
|
|
10
21
|
* byte-for-byte what gets sent.
|
|
11
22
|
*/
|
|
12
23
|
|
|
13
|
-
|
|
24
|
+
/**
|
|
25
|
+
* How a parameter or form-body field serializes, as far as the spec says:
|
|
26
|
+
* the request builder applies the OpenAPI defaults for what it leaves out.
|
|
27
|
+
*/
|
|
28
|
+
export interface ParamSerialization {
|
|
29
|
+
/** The spec's `style`; else the location's default. */
|
|
30
|
+
style?: string;
|
|
31
|
+
/** The spec's `explode`; else the style's default. */
|
|
32
|
+
explode?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PlaygroundParam extends ParamSerialization {
|
|
14
36
|
name: string;
|
|
15
37
|
in: "path" | "query" | "header";
|
|
16
38
|
required: boolean;
|
|
@@ -37,6 +59,8 @@ export interface PlaygroundBodyField {
|
|
|
37
59
|
/** A pruned, cycle-free JSON-schema subset `validate-json.ts` understands. */
|
|
38
60
|
export interface ValidationSchema {
|
|
39
61
|
type?: string;
|
|
62
|
+
/** `null` is also accepted: 3.0 `nullable`, or `"null"` in a 3.1 type array. */
|
|
63
|
+
nullable?: boolean;
|
|
40
64
|
properties?: Record<string, ValidationSchema>;
|
|
41
65
|
required?: string[];
|
|
42
66
|
items?: ValidationSchema;
|
|
@@ -47,9 +71,14 @@ export interface PlaygroundBody {
|
|
|
47
71
|
contentType: string;
|
|
48
72
|
/** Present when the schema is a flat object of primitives -> typed fields UI. */
|
|
49
73
|
fields?: PlaygroundBodyField[];
|
|
50
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Prefill for the raw editor: pretty-printed example JSON, or a raw media
|
|
76
|
+
* type's (`text/plain`, XML) string example verbatim; "" when none.
|
|
77
|
+
*/
|
|
51
78
|
example: string;
|
|
52
79
|
schema?: ValidationSchema;
|
|
80
|
+
/** A form-urlencoded body's per-field `encoding` (`style`/`explode`). */
|
|
81
|
+
encoding?: Record<string, ParamSerialization>;
|
|
53
82
|
}
|
|
54
83
|
|
|
55
84
|
export type AuthKind = "bearer" | "basic" | "apiKey" | "oauth2";
|
|
@@ -101,6 +130,38 @@ export interface RequestValues {
|
|
|
101
130
|
export const paramKey = (p: { in: string; name: string }): string =>
|
|
102
131
|
`${p.in}:${p.name}`;
|
|
103
132
|
|
|
133
|
+
/**
|
|
134
|
+
* The request header a proxied send names the headers the playground set in,
|
|
135
|
+
* comma-separated. Blume's built-in proxy forwards those and nothing else, so
|
|
136
|
+
* credentials the browser attaches on its own — HTTP Basic auth for a docs
|
|
137
|
+
* site behind a password, platform headers added in front of the docs server
|
|
138
|
+
* — never reach the documented API.
|
|
139
|
+
*/
|
|
140
|
+
export const PROXY_HEADERS_HEADER = "X-Blume-Proxy-Headers";
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* How a body's media type is put on the wire: JSON as the editor text,
|
|
144
|
+
* `application/x-www-form-urlencoded` as `name=value` pairs, and
|
|
145
|
+
* `multipart/form-data` as form parts — both from the editor's JSON object —
|
|
146
|
+
* and any other type (`text/plain`, XML) as the raw text.
|
|
147
|
+
*/
|
|
148
|
+
export type BodyEncoding = "json" | "form" | "multipart" | "raw";
|
|
149
|
+
|
|
150
|
+
/** A `+json` suffix or a `json` subtype: `application/json`, `application/vnd.api+json`. */
|
|
151
|
+
const JSON_MEDIA_TYPE = /[+/]json$/u;
|
|
152
|
+
|
|
153
|
+
/** The {@link BodyEncoding} a body's media type (parameters ignored) takes. */
|
|
154
|
+
export const bodyEncoding = (contentType: string): BodyEncoding => {
|
|
155
|
+
const type = (contentType.split(";")[0] ?? "").trim().toLowerCase();
|
|
156
|
+
if (type === "application/x-www-form-urlencoded") {
|
|
157
|
+
return "form";
|
|
158
|
+
}
|
|
159
|
+
if (type === "multipart/form-data") {
|
|
160
|
+
return "multipart";
|
|
161
|
+
}
|
|
162
|
+
return JSON_MEDIA_TYPE.test(type) ? "json" : "raw";
|
|
163
|
+
};
|
|
164
|
+
|
|
104
165
|
/** Values pre-filled from the model's precomputed examples; auth entries empty. */
|
|
105
166
|
export const defaultValues = (model: PlaygroundModel): RequestValues => ({
|
|
106
167
|
auth: Object.fromEntries(
|
|
@@ -195,48 +256,119 @@ const applyAuth = (
|
|
|
195
256
|
}
|
|
196
257
|
};
|
|
197
258
|
|
|
198
|
-
/**
|
|
259
|
+
/**
|
|
260
|
+
* A form-urlencoded body's `name=value` pairs: each field serialized like a
|
|
261
|
+
* query parameter, under the `encoding` the spec declares for it (`form`,
|
|
262
|
+
* exploded, by default — so a list repeats its name).
|
|
263
|
+
*/
|
|
264
|
+
const urlencodedBody = (
|
|
265
|
+
value: { [key: string]: JsonValue },
|
|
266
|
+
encoding: PlaygroundBody["encoding"]
|
|
267
|
+
): string =>
|
|
268
|
+
Object.entries(value)
|
|
269
|
+
.flatMap(([name, member]) => {
|
|
270
|
+
const style = encoding?.[name]?.style ?? "form";
|
|
271
|
+
return queryPairs(
|
|
272
|
+
name,
|
|
273
|
+
styledValue(member),
|
|
274
|
+
style,
|
|
275
|
+
encoding?.[name]?.explode ?? defaultExplode(style)
|
|
276
|
+
);
|
|
277
|
+
})
|
|
278
|
+
.join("&");
|
|
279
|
+
|
|
280
|
+
/** Multipart form parts in order: a list contributes one part per item. */
|
|
281
|
+
const multipartParts = (value: {
|
|
282
|
+
[key: string]: JsonValue;
|
|
283
|
+
}): [string, string][] =>
|
|
284
|
+
Object.entries(value).flatMap(([name, member]) =>
|
|
285
|
+
Array.isArray(member)
|
|
286
|
+
? member.map((item): [string, string] => [name, memberText(item)])
|
|
287
|
+
: [[name, memberText(member)]]
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* The editor text serialized for the body's media type, with a parsed mirror
|
|
292
|
+
* when it is valid JSON. A form body is built from the editor's JSON object;
|
|
293
|
+
* text that isn't one (mid-edit, or a raw media type) is sent as written.
|
|
294
|
+
*/
|
|
199
295
|
const bodyFor = (
|
|
296
|
+
body: PlaygroundBody,
|
|
200
297
|
text: string | undefined
|
|
201
|
-
): Pick<RequestSample, "body" | "bodyValue"> => {
|
|
298
|
+
): Pick<RequestSample, "body" | "bodyValue" | "formData"> => {
|
|
202
299
|
if (text === undefined || text === "") {
|
|
203
300
|
return {};
|
|
204
301
|
}
|
|
302
|
+
const encoding = bodyEncoding(body.contentType);
|
|
303
|
+
if (encoding === "raw") {
|
|
304
|
+
return { body: text };
|
|
305
|
+
}
|
|
306
|
+
let value: JsonValue;
|
|
205
307
|
try {
|
|
206
|
-
|
|
308
|
+
value = JSON.parse(text);
|
|
207
309
|
} catch {
|
|
208
|
-
// Not valid JSON (mid-edit
|
|
209
|
-
//
|
|
310
|
+
// Not valid JSON (mid-edit): still send it — the structured mirror is
|
|
311
|
+
// only a nicety for consumers of `bodyValue`.
|
|
210
312
|
return { body: text };
|
|
211
313
|
}
|
|
314
|
+
if (encoding === "json" || !isJsonObject(value)) {
|
|
315
|
+
return { body: text, bodyValue: value };
|
|
316
|
+
}
|
|
317
|
+
return encoding === "form"
|
|
318
|
+
? { body: urlencodedBody(value, body.encoding), bodyValue: value }
|
|
319
|
+
: { bodyValue: value, formData: multipartParts(value) };
|
|
212
320
|
};
|
|
213
321
|
|
|
214
|
-
/**
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
322
|
+
/**
|
|
323
|
+
* A path or header parameter's value under its `style`: an array or object
|
|
324
|
+
* parameter's JSON text becomes `dog,cat` (simple), `.dog.cat` (label), or
|
|
325
|
+
* `;tags=dog;tags=cat` (matrix) rather than its JSON.
|
|
326
|
+
*/
|
|
327
|
+
const styledParam = (
|
|
328
|
+
param: PlaygroundParam,
|
|
329
|
+
value: string,
|
|
330
|
+
encode: (text: string) => string
|
|
331
|
+
): string => {
|
|
332
|
+
const style = param.style ?? defaultStyle(param.in);
|
|
333
|
+
return templateValue(
|
|
334
|
+
param.name,
|
|
335
|
+
parseStyledValue(value, param.type),
|
|
336
|
+
style,
|
|
337
|
+
param.explode ?? defaultExplode(style),
|
|
338
|
+
encode
|
|
339
|
+
);
|
|
340
|
+
};
|
|
220
341
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
342
|
+
/**
|
|
343
|
+
* The model's path with each `{param}` filled in. An empty value substitutes
|
|
344
|
+
* the raw param name, so a blank form still renders a readable templated URL
|
|
345
|
+
* instead of `//`.
|
|
346
|
+
*/
|
|
347
|
+
const resolvePath = (model: PlaygroundModel, values: RequestValues): string => {
|
|
348
|
+
let resolved = model.path;
|
|
224
349
|
for (const param of model.params) {
|
|
225
350
|
if (param.in !== "path") {
|
|
226
351
|
continue;
|
|
227
352
|
}
|
|
228
353
|
const value = values.params[paramKey(param)] ?? "";
|
|
229
|
-
|
|
354
|
+
resolved = resolved.replace(
|
|
230
355
|
`{${param.name}}`,
|
|
231
|
-
value === "" ? param.name :
|
|
356
|
+
value === "" ? param.name : styledParam(param, value, encodeURIComponent)
|
|
232
357
|
);
|
|
233
358
|
}
|
|
359
|
+
return resolved;
|
|
360
|
+
};
|
|
234
361
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
362
|
+
/**
|
|
363
|
+
* The query parameters' `name=value` pairs in model order, each name added to
|
|
364
|
+
* `seen` so a query-borne credential can defer to it.
|
|
365
|
+
*/
|
|
366
|
+
const queryParams = (
|
|
367
|
+
model: PlaygroundModel,
|
|
368
|
+
values: RequestValues,
|
|
369
|
+
seen: Set<string>
|
|
370
|
+
): string[] => {
|
|
238
371
|
const query: string[] = [];
|
|
239
|
-
const seen = new Set<string>();
|
|
240
372
|
for (const param of model.params) {
|
|
241
373
|
if (param.in !== "query") {
|
|
242
374
|
continue;
|
|
@@ -249,10 +381,37 @@ export const buildRequest = (
|
|
|
249
381
|
continue;
|
|
250
382
|
}
|
|
251
383
|
seen.add(param.name);
|
|
384
|
+
const style = param.style ?? defaultStyle(param.in);
|
|
252
385
|
query.push(
|
|
253
|
-
|
|
386
|
+
...queryPairs(
|
|
387
|
+
param.name,
|
|
388
|
+
parseStyledValue(value, param.type),
|
|
389
|
+
style,
|
|
390
|
+
param.explode ?? defaultExplode(style)
|
|
391
|
+
)
|
|
254
392
|
);
|
|
255
393
|
}
|
|
394
|
+
return query;
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
/** THE one request builder: samples, copy buttons, and fetch all consume its output. */
|
|
398
|
+
export const buildRequest = (
|
|
399
|
+
model: PlaygroundModel,
|
|
400
|
+
values: RequestValues
|
|
401
|
+
): RequestSample => {
|
|
402
|
+
// The server's trailing slash only goes when a path is joined onto it: a
|
|
403
|
+
// GraphQL endpoint (no path) is sent exactly as configured, and
|
|
404
|
+
// `https://host/graphql/` is not always the same route as `…/graphql`.
|
|
405
|
+
const base =
|
|
406
|
+
model.path === ""
|
|
407
|
+
? values.server
|
|
408
|
+
: values.server.replace(TRAILING_SLASH, "");
|
|
409
|
+
|
|
410
|
+
// Query params with a value contribute in model order; a query-borne auth
|
|
411
|
+
// credential appends after — unless the spec also declares that name as an
|
|
412
|
+
// explicit query parameter, whose (better) example wins.
|
|
413
|
+
const seen = new Set<string>();
|
|
414
|
+
const query = queryParams(model, values, seen);
|
|
256
415
|
|
|
257
416
|
// Auth first, so a spec that also declares the credential as an explicit
|
|
258
417
|
// header parameter overrides it below with its own (better) example.
|
|
@@ -266,12 +425,18 @@ export const buildRequest = (
|
|
|
266
425
|
// Required headers emit even when blank, mirroring the query rule above —
|
|
267
426
|
// except a blank one never clobbers a credential auth already placed
|
|
268
427
|
// under the same name.
|
|
269
|
-
if (value !== ""
|
|
428
|
+
if (value !== "") {
|
|
429
|
+
headers[param.name] = styledParam(param, value, (text) => text);
|
|
430
|
+
} else if (param.required && headers[param.name] === undefined) {
|
|
270
431
|
headers[param.name] = value;
|
|
271
432
|
}
|
|
272
433
|
}
|
|
273
434
|
|
|
274
|
-
const { body, bodyValue } = model.body
|
|
435
|
+
const { body, bodyValue, formData } = model.body
|
|
436
|
+
? bodyFor(model.body, values.body)
|
|
437
|
+
: {};
|
|
438
|
+
// Multipart parts carry no Content-Type here: the client (curl, fetch,
|
|
439
|
+
// requests) writes it along with the boundary that separates the parts.
|
|
275
440
|
if (body !== undefined && model.body) {
|
|
276
441
|
headers["Content-Type"] = model.body.contentType;
|
|
277
442
|
}
|
|
@@ -280,8 +445,9 @@ export const buildRequest = (
|
|
|
280
445
|
return {
|
|
281
446
|
body,
|
|
282
447
|
bodyValue,
|
|
448
|
+
formData,
|
|
283
449
|
headers,
|
|
284
450
|
method: model.method.toUpperCase(),
|
|
285
|
-
url: `${base}${
|
|
451
|
+
url: `${base}${resolvePath(model, values)}${search}`,
|
|
286
452
|
};
|
|
287
453
|
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import {
|
|
2
|
+
objectProperties,
|
|
3
|
+
refName,
|
|
4
|
+
resolveSchema,
|
|
5
|
+
typeLabel,
|
|
6
|
+
} from "./helpers.ts";
|
|
7
|
+
import type { SchemaLike, SpecValue } from "./helpers.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The expansion plan behind the schema tables (`SchemaTable.astro` and
|
|
11
|
+
* `SchemaProperty.astro`). Every nested object is server-rendered in full
|
|
12
|
+
* inside a collapsed `<details>`, so the plan is the page's weight: expanding
|
|
13
|
+
* each named schema wherever it appears — stopping only at a model nested in
|
|
14
|
+
* itself — grows exponentially with cross-references (twelve schemas that
|
|
15
|
+
* each reference four others render tens of thousands of nested tables for
|
|
16
|
+
* one request body).
|
|
17
|
+
*
|
|
18
|
+
* So a named schema expands wherever it appears in the first
|
|
19
|
+
* {@link REPEAT_DEPTH} named levels, and deeper than that only where it
|
|
20
|
+
* appears first in the tree, breadth-first; a later mention shows its name
|
|
21
|
+
* alone. Beyond the first levels each named schema expands at most once, so
|
|
22
|
+
* the tree stays proportional to the spec instead of to the number of paths
|
|
23
|
+
* through it, while the shallow nesting typical specs use — `billing` and
|
|
24
|
+
* `shipping` both an `Address` — renders exactly as before.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Named-schema nesting depth (the root being 0) up to which a named schema
|
|
29
|
+
* expands at every mention, even one already expanded elsewhere in the tree.
|
|
30
|
+
*/
|
|
31
|
+
export const REPEAT_DEPTH = 2;
|
|
32
|
+
|
|
33
|
+
/** A place in the tree a node is planned into; filled in breadth-first. */
|
|
34
|
+
export interface SchemaSlot {
|
|
35
|
+
node: SchemaNode;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** One property row of an object table. */
|
|
39
|
+
export interface SchemaRow {
|
|
40
|
+
name: string;
|
|
41
|
+
required: boolean;
|
|
42
|
+
schema: SchemaLike;
|
|
43
|
+
/** The row's disclosure contents; absent when the row has nothing to show. */
|
|
44
|
+
children?: SchemaSlot;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** What one schema table renders. */
|
|
48
|
+
export type SchemaNode =
|
|
49
|
+
/** A named schema nested inside itself. */
|
|
50
|
+
| { kind: "circular"; name: string }
|
|
51
|
+
/** A named schema expanded elsewhere in this tree: its name only. */
|
|
52
|
+
| { kind: "named"; name: string }
|
|
53
|
+
| { kind: "array"; itemsLabel: string; items?: SchemaSlot }
|
|
54
|
+
| {
|
|
55
|
+
kind: "branches";
|
|
56
|
+
label: "One of" | "Any of";
|
|
57
|
+
branches: { label: string; slot: SchemaSlot }[];
|
|
58
|
+
/**
|
|
59
|
+
* Properties the schema declares beside its `oneOf`/`anyOf`, which
|
|
60
|
+
* every variant shares; absent when it declares none.
|
|
61
|
+
*/
|
|
62
|
+
rows?: SchemaRow[];
|
|
63
|
+
}
|
|
64
|
+
| { kind: "properties"; rows: SchemaRow[] }
|
|
65
|
+
| { kind: "type"; label: string };
|
|
66
|
+
|
|
67
|
+
const isString = (value: SpecValue): value is string =>
|
|
68
|
+
typeof value === "string";
|
|
69
|
+
|
|
70
|
+
const typesOf = (schema: SchemaLike): (string | undefined)[] =>
|
|
71
|
+
Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
72
|
+
|
|
73
|
+
/** Whether a schema has nested fields a row can disclose. */
|
|
74
|
+
const hasNestedFields = (candidate: SchemaLike): boolean =>
|
|
75
|
+
Boolean(
|
|
76
|
+
candidate.properties ||
|
|
77
|
+
candidate.allOf ||
|
|
78
|
+
candidate.oneOf ||
|
|
79
|
+
candidate.anyOf ||
|
|
80
|
+
isString(candidate.$ref)
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
/** A named schema waiting for its breadth-first turn. */
|
|
84
|
+
interface PendingRef {
|
|
85
|
+
ancestors: string[];
|
|
86
|
+
name: string;
|
|
87
|
+
schema: SchemaLike;
|
|
88
|
+
slot: SchemaSlot;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Plan the table tree for one schema (a request body, a response, a payload). */
|
|
92
|
+
export const schemaTree = (
|
|
93
|
+
root: SchemaLike,
|
|
94
|
+
schemas: Record<string, SchemaLike>
|
|
95
|
+
): SchemaNode => {
|
|
96
|
+
const queue: PendingRef[] = [];
|
|
97
|
+
const expanded = new Set<string>();
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* A table for `schema`, where `ancestors` are the named schemas already
|
|
101
|
+
* open above it. A `$ref` waits in the queue, so every mention at one depth
|
|
102
|
+
* is planned before any deeper one; `resolved` plans a dequeued schema's
|
|
103
|
+
* own body instead.
|
|
104
|
+
*/
|
|
105
|
+
const table = (
|
|
106
|
+
schema: SchemaLike,
|
|
107
|
+
ancestors: string[],
|
|
108
|
+
resolved = false
|
|
109
|
+
): SchemaSlot => {
|
|
110
|
+
if (!resolved && isString(schema.$ref)) {
|
|
111
|
+
const name = refName(schema.$ref);
|
|
112
|
+
if (ancestors.includes(name)) {
|
|
113
|
+
return { node: { kind: "circular", name } };
|
|
114
|
+
}
|
|
115
|
+
const slot: SchemaSlot = { node: { kind: "named", name } };
|
|
116
|
+
queue.push({ ancestors, name, schema, slot });
|
|
117
|
+
return slot;
|
|
118
|
+
}
|
|
119
|
+
if (typesOf(schema).includes("array")) {
|
|
120
|
+
// Items stay unresolved, so a self-referential item `$ref` is still
|
|
121
|
+
// recognized as the circle it is.
|
|
122
|
+
const { items } = schema;
|
|
123
|
+
return {
|
|
124
|
+
node: items
|
|
125
|
+
? {
|
|
126
|
+
items: table(items, ancestors),
|
|
127
|
+
itemsLabel: typeLabel(items),
|
|
128
|
+
kind: "array",
|
|
129
|
+
}
|
|
130
|
+
: { itemsLabel: typeLabel({}), kind: "array" },
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// A row discloses nested structure — never a model inside itself.
|
|
134
|
+
const rowChildren = (property: SchemaLike): SchemaSlot | undefined => {
|
|
135
|
+
if (
|
|
136
|
+
isString(property.$ref) &&
|
|
137
|
+
ancestors.includes(refName(property.$ref))
|
|
138
|
+
) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
const target = resolveSchema(schemas, property);
|
|
142
|
+
const items = typesOf(target).includes("array")
|
|
143
|
+
? resolveSchema(schemas, target.items)
|
|
144
|
+
: null;
|
|
145
|
+
return hasNestedFields(target) || (items && hasNestedFields(items))
|
|
146
|
+
? table(property, ancestors)
|
|
147
|
+
: undefined;
|
|
148
|
+
};
|
|
149
|
+
const { properties, required } = objectProperties(schema, schemas);
|
|
150
|
+
const rows: SchemaRow[] = properties.map(([name, property]) => ({
|
|
151
|
+
children: rowChildren(property),
|
|
152
|
+
name,
|
|
153
|
+
required: required.has(name),
|
|
154
|
+
schema: property,
|
|
155
|
+
}));
|
|
156
|
+
// Shared properties beside a `oneOf`/`anyOf` (`amount` and `currency`
|
|
157
|
+
// next to `Card | BankAccount`) render above the variants, planned first
|
|
158
|
+
// as they read first.
|
|
159
|
+
const branches = schema.oneOf ?? schema.anyOf;
|
|
160
|
+
if (branches) {
|
|
161
|
+
const node: Extract<SchemaNode, { kind: "branches" }> = {
|
|
162
|
+
branches: branches.map((branch, index) => ({
|
|
163
|
+
label: typeLabel(branch) || `Option ${index + 1}`,
|
|
164
|
+
slot: table(branch, ancestors),
|
|
165
|
+
})),
|
|
166
|
+
kind: "branches",
|
|
167
|
+
label: schema.oneOf ? "One of" : "Any of",
|
|
168
|
+
};
|
|
169
|
+
if (rows.length > 0) {
|
|
170
|
+
node.rows = rows;
|
|
171
|
+
}
|
|
172
|
+
return { node };
|
|
173
|
+
}
|
|
174
|
+
if (rows.length > 0) {
|
|
175
|
+
return { node: { kind: "properties", rows } };
|
|
176
|
+
}
|
|
177
|
+
return { node: { kind: "type", label: typeLabel(schema) } };
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const tree = table(root, []);
|
|
181
|
+
// The queue grows while it drains, in depth order: every mention at one
|
|
182
|
+
// named depth is queued before the first one at the next.
|
|
183
|
+
for (const pending of queue) {
|
|
184
|
+
const depth = pending.ancestors.length;
|
|
185
|
+
if (depth > REPEAT_DEPTH && expanded.has(pending.name)) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
expanded.add(pending.name);
|
|
189
|
+
pending.slot.node = table(
|
|
190
|
+
resolveSchema(schemas, pending.schema),
|
|
191
|
+
[...pending.ancestors, pending.name],
|
|
192
|
+
true
|
|
193
|
+
).node;
|
|
194
|
+
}
|
|
195
|
+
return tree.node;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Whether a row gets a disclosure: it has nested structure, and that structure
|
|
200
|
+
* isn't just the name of a schema expanded elsewhere (directly, or as the
|
|
201
|
+
* items of an array).
|
|
202
|
+
*/
|
|
203
|
+
export const rowExpands = (row: SchemaRow): boolean => {
|
|
204
|
+
const node = row.children?.node;
|
|
205
|
+
if (!node || node.kind === "named") {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
return !(node.kind === "array" && node.items?.node.kind === "named");
|
|
209
|
+
};
|