feat(page): OpenAPI bridge — ingest OpenAPI 3.x operations into the kit#46
Merged
Conversation
Point `c.openapi` at an OpenAPI 3.x spec and render a whole endpoint with one `operation "createInvoice"` call — no hand-restatement. The operation's method/path/summary become a DocsUI::Endpoint badge; its parameters and request body become FieldTables; its 4xx/5xx responses an ErrorTable; its x-codeSamples (or a generated RequestExample) the client tabs; and its first 2xx example a JsonResponse. Because it's composed from the existing kit, the .md twin, llms.txt, search, and MCP surfaces derive from it for free. Closes the last big restatement source the DX overhaul (#8) deferred until the #14/#15 render targets shipped. ## What's new - `DocsKit::OpenApi.load` → a narrow, gem-owned object model (`Document` + `Operation` + `Schema`). Stdlib YAML/JSON — no parser dependency. Local $ref resolution (cycle-safe, depth-capped), allOf merge, enum/oneOf/anyOf type labels, example synthesis, x-codeSamples (both spellings). Loud on lookup (`OperationNotFound` names the ids; `UnsupportedRef` on an external $ref), graceful on missing examples/blocks. - `c.openapi` config knob (String/Pathname/Hash, default nil → bridge off, fully backwards compatible). `#openapi_document` memoizes and reloads on the file's mtime change. - `DocsUI::OpenApiOperation` component + the lowercase `operation` page helper. - `DocsUI::ErrorTable#type` is now optional (OpenAPI has no canonical error-type field) — a type-less row gets the em-dash; rows with `type:` render exactly as before. ## Install path & docs - Generator initializer documents the commented `c.openapi` knob; the `operation` helper is added to the AGENTS.md + write-docs-page skill contracts. `docs-kit new` inherits both via `docs_kit:install`. - README gains an "OpenAPI bridge" subsection (spec → component mapping table). - Dogfood: `docs/openapi.yaml` + `c.openapi` + a live "OpenAPI bridge" page. ## Test Coverage - `spec/docs_kit/open_api/{document,operation,schema}_spec.rb` — the model: loading, lookup, $ref/cycle/allOf, row derivation, example precedence, code samples. - `spec/docs_ui/open_api_operation_spec.rb` — the component renders each part through the kit; x-codeSamples override; block passthrough. - `spec/docs_ui/page_helpers_spec.rb` — the `operation` helper. - `spec/docs_kit/configuration_spec.rb` — the knob (default, types, memoize, mtime reload, raise-when-unset). - `spec/docs_ui/error_table_spec.rb` — optional type. - `spec/generators/install_generator_spec.rb` — the commented knob lands. ## Verification - [x] bundle exec rake (rspec + rubocop) — 620 examples, 0 failures; 95.9% line coverage; RuboCop clean - [x] Dogfood page renders end-to-end through a real Rails view context, and its .md twin derives (FieldTable/ErrorTable/code fences) with no export code - [x] Backwards compatible — a site without c.openapi is byte-identical Closes #40 Claude-Session: https://claude.ai/code/session_01FPQb6z3YwcKRMbvoJhdxnX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #40. Point
c.openapiat an OpenAPI 3.x spec and render a whole endpoint with oneoperation "createInvoice"call — zero hand-restatement. This closes the last big restatement source the DX overhaul (#8) deferred until the #14/#15 render targets shipped.One
operationcall expands to a fullDocsUI::Section:operationId+summary+ method/pathDocsUI::Endpointbadgedescriptionparameters(query/path)DocsUI::FieldTablerequestBodyschema ($ref,allOf, nested)FieldTable(nested names dotted:customer.id)4xx/5xxresponsesDocsUI::ErrorTable(errortypefrom a response example)x-codeSamples/x-code-samplesDocsUI::Exampletabs (a lone sample → a plainCode)DocsUI::RequestExample2xxexampleDocsUI::JsonResponseBecause it's composed entirely from the existing kit, the
.mdtwin,llms.txt, search, and MCP surfaces all derive from it for free — verified on the dogfood page.Design
DocsKit::OpenApi::Document+Operation+Schema) — no runtime parser dependency (the gemspec is deliberately minimal). The model exposes only what the render targets consume (field rows, error rows, example bodies, code samples).openapi3_parserdependency (every site pays for an opt-in feature; its validation can reject real-world specs), and build-time codegen (regenerated pages drift from the spec — runtime derivation is what makes it zero-restatement).operationIdraisesDocsKit::OpenApi::OperationNotFoundnaming the available ids; an external/remote$refraisesDocsKit::OpenApi::UnsupportedRef. Missing examples/blocks degrade (no body table, no response block).$refonly, resolved cycle-safely and depth-capped;allOfshallow-merged;oneOf/anyOfrendered as aone of: A | Btype label.ErrorTable#typeis now optional — OpenAPI has no canonical error-type field. A type-less row gets the em-dash; rows passingtype:render exactly as before (backwards compatible).What's new
DocsKit::OpenApi.load+ the object model (lib/docs_kit/open_api.rb,open_api/{document,operation,schema}.rb).c.openapiconfig knob (String/Pathname/Hash, defaultnil→ bridge off).#openapi_documentmemoizes and reloads on the file's mtime change.DocsUI::OpenApiOperationcomponent + the lowercaseoperationpage helper.Install path & docs
c.openapiknob; theoperationhelper is added to the AGENTS.md + write-docs-page skill contracts.docs-kit newinherits both viadocs_kit:install.docs/openapi.yaml+c.openapiset + a live "OpenAPI bridge" page (/docs/openapi) that documents the bridge and renders three real operations.Test plan
spec/docs_kit/open_api/{document,operation,schema}_spec.rb— loading (YAML/JSON/Hash/Pathname), lookup by id and by verb+path, local$ref/cycle/allOf, parameter/body row derivation (nested dotting, enum labels, array-of), error rows + optional type, example precedence,x-codeSamples(both spellings).spec/docs_ui/open_api_operation_spec.rb— each part renders through the kit; both-tables labelling;x-codeSamplesoverride (1 →Code, ≥2 →Example);clients:passthrough; block passthrough.spec/docs_ui/page_helpers_spec.rb— theoperationhelper (lookup,clients:, block, raise).spec/docs_kit/configuration_spec.rb— the knob (default, types, memoize, mtime reload, raise-when-unset).spec/docs_ui/error_table_spec.rb— optional type.spec/generators/install_generator_spec.rb— the commented knob lands in the generated initializer.Verification
bundle exec rake(rspec + rubocop) — 620 examples, 0 failures, 95.9% line coverage, RuboCop clean (113 files).mdtwin derives (FieldTable/ErrorTable/code fences) with no export codec.openapiis byte-identical;ErrorTablerows passingtype:unchangedh3uses utilities already inprose.rb/header.rb/shell.rb)https://claude.ai/code/session_01FPQb6z3YwcKRMbvoJhdxnX