From 4c777d9444e6d184ee2adb832cec5e5284e27b11 Mon Sep 17 00:00:00 2001 From: Dinh Le Date: Mon, 7 Sep 2026 14:59:54 +0700 Subject: [PATCH 1/2] chore: drop the downgrader build script in favor of prepack The types package already relied on prepack alone; the downgrader kept a duplicate build script that nothing referenced. pnpm pack still runs unbuild through prepack. --- packages/downgrader/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/downgrader/package.json b/packages/downgrader/package.json index 5396da8..c91ba42 100644 --- a/packages/downgrader/package.json +++ b/packages/downgrader/package.json @@ -58,7 +58,6 @@ } }, "scripts": { - "build": "unbuild", "prepack": "unbuild", "type:check": "tsc -b" }, From 5f2c67127833d9c60ee6ee40e735a30c384784e9 Mon Sep 17 00:00:00 2001 From: Dinh Le Date: Mon, 7 Sep 2026 14:59:58 +0700 Subject: [PATCH 2/2] docs: rewrite READMEs purpose-first with the orpc header, add MIT LICENSE Every README now opens with what the project or package is for, uses the orpc badge block (codecov, npm downloads, license, Discord, DeepWiki), and ends with a License section after the generated sponsors block. The downgrader mapping tables are tightened and gain two previously undocumented behaviors. The LICENSE file backs the MIT declaration already in each package.json. --- LICENSE | 21 +++++ README.md | 40 ++++++++- packages/downgrader/README.md | 160 ++++++++++++++++++++++----------- packages/types/README.md | 72 ++++++++++----- packages/types/tests/README.md | 12 +-- 5 files changed, 227 insertions(+), 78 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3767203 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 MiddleAPI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index e12aba3..94896b3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,38 @@ -# OAS +

OpenAPI Spec

+ +
+ + codecov + + + weekly downloads + + + MIT License + + + Discord + + + Ask DeepWiki + +
+ +TypeScript tooling for the [OpenAPI Specification](https://spec.openapis.org/), maintained by [middleapi](https://github.com/middleapi). It lets you work with OpenAPI 3.0, 3.1, and 3.2 documents from one place: precise types for each version, and converters that move a document from a newer version to an older one without losing anything the older version can still express. + +| Package | Description | +| --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| [`@openapi-spec/types`](https://github.com/middleapi/openapi-spec/blob/main/packages/types/README.md) | TypeScript types for OpenAPI 3.0, 3.1, and 3.2, with the specification text as JSDoc on every field | +| [`@openapi-spec/downgrader`](https://github.com/middleapi/openapi-spec/blob/main/packages/downgrader/README.md) | Downgrade documents and Schema Objects one minor version at a time: 3.2 to 3.1 and 3.1 to 3.0 | + +## Development + +```bash +pnpm install +pnpm test +pnpm lint +pnpm type:check +``` ## Sponsors @@ -83,3 +117,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he With thanks to [36 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get openapi-spec here. + +## License + +Distributed under the MIT License. See [LICENSE](https://github.com/middleapi/openapi-spec/blob/main/LICENSE) for more information. diff --git a/packages/downgrader/README.md b/packages/downgrader/README.md index fe14099..2887047 100644 --- a/packages/downgrader/README.md +++ b/packages/downgrader/README.md @@ -1,10 +1,30 @@ -# @openapi-spec/downgrader - -Downgrade [OpenAPI Specification](https://spec.openapis.org/) documents one minor version at a time: 3.2 → 3.1 and 3.1 → 3.0. Each converter works on an entire document or on a single Schema Object. - -- **Never throws**: malformed parts are deep-copied through unchanged instead of failing the whole conversion, and cyclic object graphs (e.g. the output of a `$ref` dereferencer) don't recurse forever — they are converted with their cycles preserved, a subtree that cycles back into an ancestor pointing at that ancestor's converted form. Only pathologically deep nesting (thousands of levels) can still exhaust the call stack. -- **Never mutates**: the input document is left untouched. -- **Extension-preserving, never extension-inventing**: existing `x-` keys and unknown keys always survive, while constructs the target version cannot express are converted where an equivalent exists and removed otherwise. +

OpenAPI Spec

+ +
+ + codecov + + + weekly downloads + + + MIT License + + + Discord + + + Ask DeepWiki + +
+ +`@openapi-spec/downgrader` downgrades [OpenAPI Specification](https://spec.openapis.org/) documents one minor version at a time: 3.2 to 3.1 and 3.1 to 3.0. Use it when you author against a newer version than your tools accept, such as a code generator, gateway, or validator that stops at 3.0 or 3.1. Each converter handles a whole document or a single Schema Object. + +Every converter follows the same contract: + +- **Never throws.** Malformed parts are deep-copied through unchanged instead of failing the whole conversion. Cyclic object graphs, such as the output of a `$ref` dereferencer, convert with their cycles preserved. Only pathologically deep nesting (thousands of levels) can still exhaust the call stack. +- **Never mutates.** The input is left untouched and the result is a new object. +- **Preserves extensions, never invents them.** `x-` keys and unknown keys survive. Constructs the target version cannot express are converted where an equivalent exists and removed otherwise. ## Usage @@ -19,68 +39,102 @@ import { const v31 = downgradeSpecV32ToV31(v32Document) const v30 = downgradeSpecV31ToV30(v31Document) -// There is intentionally no direct 3.2 → 3.0 converter; compose the steps: +// There is no direct 3.2 to 3.0 converter on purpose. Compose the steps: const downgraded = downgradeSpecV31ToV30(downgradeSpecV32ToV31(v32Document)) -// Schema Objects can be converted standalone: -const schema = downgradeSchemaV31ToV30({ type: ['string', 'null'] }) -// { type: "string", nullable: true } +// Schema Objects convert on their own: +downgradeSchemaV31ToV30({ type: ['string', 'null'] }) +// { type: 'string', nullable: true } ``` -## 3.2 → 3.1 +| Function | Input | Output | +| ------------------------- | ------------------- | --------------------------------------- | +| `downgradeSpecV32ToV31` | 3.2 `OpenAPIObject` | 3.1 `OpenAPIObject` | +| `downgradeSchemaV32ToV31` | 3.2 `SchemaObject` | 3.1 `SchemaObject` | +| `downgradeSpecV31ToV30` | 3.1 `OpenAPIObject` | 3.0 `OpenAPIObject` | +| `downgradeSchemaV31ToV30` | 3.1 `SchemaObject` | 3.0 `SchemaObject` or `ReferenceObject` | -Schema Objects pass through unchanged: the 3.2 Schema Object keyword set is identical to 3.1's (3.2 defines its own dialect URI, but only the OAS base vocabulary gained fields), and the 3.2-only fields (discriminator `defaultMapping`, XML `nodeType`) are deliberately retained. Two caveats: the standard OpenAPI 3.1 document schema tolerates them (Schema Object internals are open there), but the strict OAS 3.1 base-vocabulary meta-schema closes the XML and Discriminator Objects to their fixed fields plus `x-`, so a base-vocabulary validator will flag them; and 3.1 tooling will not act on them — in particular a `defaultMapping` fallback stops taking effect (`nodeType` is recovered on the 3.1 → 3.0 hop). +All types come from [`@openapi-spec/types`](https://github.com/middleapi/openapi-spec/blob/main/packages/types/README.md). -Converted: +## 3.2 → 3.1 -| 3.2 construct | 3.1 result | -| ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `openapi: 3.2.x` | `openapi: 3.1.2` | -| `jsonSchemaDialect` naming a 3.2 OAS dialect | `https://spec.openapis.org/oas/3.1/dialect/base` (the 3.2 dialect only extends the 3.1 base vocabulary); other dialects pass through | -| `components.mediaTypes` and content-map `$ref`s to them | references inlined, the component map removed; content entries whose reference cannot be inlined (external, unknown, or cyclic targets) are removed, as 3.1 content maps cannot hold references — a parameter or header losing its entire `content` that way is removed with it (3.1 requires exactly one entry there) | -| Media type `itemSchema` without a sibling `schema` | `schema: { type: "array", items: … }` (the 3.2 sequential media type data model) | -| Response `summary` when no `description` exists | promoted to `description` (required in 3.1, so `""` is synthesized as a last resort) | -| Example `dataValue` / `serializedValue` when `value` and `externalValue` are absent | promoted to `value` (in that order) | -| Parameter `style: "cookie"` | removed, letting the 3.1 default `form` apply | +Schema Objects pass through unchanged. 3.2 keeps the 3.1 JSON Schema keyword set and only adds two fields to the OAS vocabulary, `discriminator.defaultMapping` and `xml.nodeType`, and both are kept. 3.1 tooling ignores them, so a `defaultMapping` fallback stops taking effect, while `nodeType` is picked up again on the 3.1 → 3.0 hop. The standard OpenAPI 3.1 document schema accepts them, but the strict OAS 3.1 base-vocabulary meta-schema closes the XML and Discriminator Objects and will flag them. -Removed (no 3.1 equivalent): `$self`, server `name`, tag `summary`/`parent`/`kind`, the `query` operation and `additionalOperations` of Path Items, `in: "querystring"` parameters (from parameter lists and `components.parameters`, together with references to the removed component entries, following chains of reference aliases), `allowReserved` on non-query parameters, media type `description`, media type / encoding `prefixEncoding`, `itemEncoding`, and nested `encoding`, a media type `itemSchema` beside an existing `schema`, response `summary` beside an existing `description`, OAuth `deviceAuthorization` flows, and security scheme `oauth2MetadataUrl` and `deprecated`. +Converted: -Known limitations: security requirements using URI keys and `$self`-relative reference resolution are passed through unchanged, and so is a `$schema` keyword inside a Schema Object that names the 3.2 dialect. +| 3.2 construct | 3.1 result | +| -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `openapi: 3.2.x` | `openapi: 3.1.2` | +| `jsonSchemaDialect` naming a 3.2 OAS dialect | `https://spec.openapis.org/oas/3.1/dialect/base`; other dialects pass through | +| `components.mediaTypes` and content-map `$ref`s to it | references inlined and the component map removed. Entries whose target cannot be inlined (external, unknown, or cyclic) are removed, since 3.1 content maps cannot hold references. A parameter or header that loses its entire `content` that way is removed too, because 3.1 requires exactly one entry there | +| media type `itemSchema` without a sibling `schema` | `schema: { type: "array", items: … }`, the sequential media type data model | +| response `summary` without a `description` | promoted to `description`; `""` when neither exists, since 3.1 requires it | +| example `dataValue` / `serializedValue` without `value` or `externalValue` | promoted to `value`, `dataValue` taking precedence | +| parameter `style: "cookie"` | removed so the 3.1 default `form` applies | + +Removed, with no 3.1 equivalent: + +- `$self` +- server `name` +- tag `summary`, `parent`, and `kind` +- the Path Item `query` operation and `additionalOperations` +- `in: "querystring"` parameters, in parameter lists and in `components.parameters`, together with references to removed component parameters and headers (chains of reference aliases included) +- `allowReserved` on non-query parameters +- media type `description` +- `prefixEncoding`, `itemEncoding`, and nested `encoding` on media types and encodings +- `itemSchema` beside an existing `schema`, and response `summary` beside an existing `description` +- OAuth `deviceAuthorization` flows +- security scheme `oauth2MetadataUrl` and `deprecated` + +Known limitations: security requirements keyed by URI, `$self`-relative reference resolution, and a `$schema` keyword inside a Schema Object that names the 3.2 dialect all pass through unchanged. ## 3.1 → 3.0 Converted: -| 3.1 construct | 3.0 result | -| ----------------------------------------------- | ---------------------------------------------------------------------- | -| `openapi: 3.1.x` | `openapi: 3.0.4` | -| missing `paths` | `{}` (required in 3.0) | -| missing operation `responses` | `{ "default": { "description": "" } }` (required and non-empty in 3.0) | -| Reference `summary` / `description` overrides | removed (3.0 references stand alone) | -| Security requirement roles on non-OAuth schemes | emptied (`[]`) | +| 3.1 construct | 3.0 result | +| ---------------------------------------------------------- | ---------------------------------------------------------------------- | +| `openapi: 3.1.x` | `openapi: 3.0.4` | +| missing `paths` | `{}` (required in 3.0) | +| missing operation `responses` | `{ "default": { "description": "" } }` (required and non-empty in 3.0) | +| path parameters without `required: true` | `required: true` added (mandatory for `in: "path"`) | +| Reference Object `summary` / `description` | removed (3.0 references carry no overrides) | +| security requirement scopes on `apiKey` and `http` schemes | emptied to `[]` | + +Removed, with no 3.0 equivalent: -Removed (no 3.0 equivalent): `webhooks`, `components.pathItems` (Path Item `$ref`s pointing at it, in `paths` and in callbacks, are inlined instead — following chains of references, with the referencing Path Item's own fields winning over inlined ones where both define a field; a reference that cannot be inlined, such as an unknown or cyclic target, is left untouched and will dangle), `jsonSchemaDialect`, `info.summary`, `license.identifier`, and `mutualTLS` security schemes (reference aliases to them included) — their names are stripped from every security requirement, requirements that referenced only such schemes are removed, and a `security` list emptied that way is removed entirely, since an explicit empty list means "no security required" and would make an operation public. +- `webhooks` +- `jsonSchemaDialect` +- `info.summary` and `license.identifier` +- `components.pathItems`. Path Item `$ref`s to it, in `paths` and in callbacks, are inlined first, following reference chains, with the referencing Path Item's own fields winning over inlined ones. A reference that cannot be inlined (unknown or cyclic target) is left as is and will dangle. +- `mutualTLS` security schemes, reference aliases included. Their names are stripped from every security requirement, a requirement left empty is removed, and a `security` list left empty is removed entirely, since an explicit empty list means "no security required" and would make the operation public. Schema Objects: -| 3.1 construct | 3.0 result | -| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `true` / `false` boolean schemas | `{}` / `{ not: {} }` | -| `$ref` with sibling keywords | siblings kept, `$ref` wrapped into `allOf` | -| `type: ["T", "null"]` | `type: "T"` plus `nullable: true` | -| `enum: []` / duplicate `required` entries | `enum` removed / `required` deduplicated (3.0 requires a non-empty `enum` and unique `required`) | -| `type: "null"` | `nullable: true` plus `enum: [null]`; a sibling `enum`/`const` is intersected with the null type — an `enum` containing `null` collapses to `[null]`, and a sibling excluding `null` yields a match-nothing schema (`not: {}`), since the source accepted no value | -| `type` with several non-null entries | `anyOf` of single-type schemas | -| `const` | single-value `enum` | -| numeric `exclusiveMinimum` / `exclusiveMaximum` | bound plus boolean flag (the tighter bound wins) | -| `examples` | first entry becomes `example` when none exists | -| `contentEncoding: base64` | `format: byte` | -| `contentMediaType: application/octet-stream` | `format: binary` | -| `type: "array"` without `items` | `items: {}` is added (required in 3.0) | -| XML `nodeType` (carried over from a 3.2 chain) | `attribute: true` / `wrapped: true` where expressible, then removed (3.0 forbids unknown XML Object fields) | -| `$schema`, `$id`, `$defs`, `$anchor`, `$dynamicRef`/`$dynamicAnchor`, `$vocabulary`, `$comment`, `if`/`then`/`else`, `dependentSchemas`/`dependentRequired`, `prefixItems` (and its trailing `items`), `contains`/`minContains`/`maxContains`, `patternProperties` (and its sibling `additionalProperties`, whose meaning would otherwise tighten onto the pattern-matched keys), `propertyNames`, `unevaluatedItems`/`unevaluatedProperties`, `contentSchema` | removed — in positive schema positions dropping these only loosens validation, the safe direction for a downgrade | - -Known limitations: `$ref`s that point into dropped keywords (`#/…/$defs/…` pointers, `$anchor` targets, `$id`-based bases) will dangle — hoist reusable subschemas into `components.schemas` before downgrading. Arbitrary non-standard schema keywords are preserved per the extension-preserving contract, even though the official 3.0 schema forbids unknown Schema Object fields. Dropping keywords inside `not` (where loosening the operand tightens the whole) or inside `oneOf` branches (where loosening one branch can break exclusivity) can shift what validates. +| 3.1 construct | 3.0 result | +| ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `true` / `false` boolean schemas | `{}` / `{ not: {} }` | +| `$ref` with sibling keywords | siblings kept, `$ref` moved into `allOf` | +| `type: ["T", "null"]` | `type: "T"` plus `nullable: true` | +| `type` with several non-null entries | `anyOf` of single-type schemas, each `nullable` when `null` was listed | +| `type: "null"` | `nullable: true` plus `enum: [null]`. A sibling `enum` or `const` is intersected with the null type: an `enum` containing `null` collapses to `[null]`, and one excluding it yields `not: {}`, since the source accepted no value | +| `const` | single-value `enum`, plus `nullable: true` when the value is `null` | +| numeric `exclusiveMinimum` / `exclusiveMaximum` | `minimum` / `maximum` plus the boolean flag; a tighter existing bound wins | +| `examples` | first entry becomes `example` when none exists | +| `contentEncoding: base64` | `format: byte` when no `format` exists | +| `contentMediaType: application/octet-stream` without `contentEncoding` | `format: binary` when no `format` exists | +| `type: "array"` without `items` | `items: {}` added (required in 3.0) | +| `enum: []` | removed (3.0 requires a non-empty `enum`) | +| `required: []` / duplicate `required` entries | removed / deduplicated (3.0 requires a non-empty, unique `required`) | +| XML `nodeType`, carried over from a 3.2 chain | `attribute: true` / `wrapped: true` where expressible, then removed (3.0 forbids unknown XML Object fields) | + +Removed, with no 3.0 equivalent: `$schema`, `$id`, `$defs`, `$anchor`, `$dynamicRef`, `$dynamicAnchor`, `$vocabulary`, `$comment`, `if` / `then` / `else`, `dependentSchemas`, `dependentRequired`, `prefixItems` (with its trailing `items`), `contains`, `minContains`, `maxContains`, `patternProperties` (with its sibling `additionalProperties`, whose meaning would otherwise tighten onto the pattern-matched keys), `propertyNames`, `unevaluatedItems`, `unevaluatedProperties`, and `contentSchema`. In positive schema positions dropping these only loosens validation, the safe direction for a downgrade. + +Known limitations: + +- `$ref`s into dropped keywords (`#/…/$defs/…` pointers, `$anchor` targets, `$id`-based bases) will dangle. Hoist reusable subschemas into `components.schemas` before downgrading. +- Non-standard schema keywords are preserved per the extension contract, even though the official 3.0 schema forbids unknown Schema Object fields. +- Dropping keywords inside `not`, where loosening the operand tightens the whole, or inside `oneOf` branches, where loosening one branch can break exclusivity, can change what validates. ## Sponsors @@ -165,3 +219,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he With thanks to [36 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get openapi-spec here. + +## License + +Distributed under the MIT License. See [LICENSE](https://github.com/middleapi/openapi-spec/blob/main/LICENSE) for more information. diff --git a/packages/types/README.md b/packages/types/README.md index c006eab..cf035be 100644 --- a/packages/types/README.md +++ b/packages/types/README.md @@ -1,28 +1,50 @@ -# @openapi-spec/types - -TypeScript types for the [OpenAPI Specification](https://spec.openapis.org/), covering versions 3.0, 3.1, and 3.2 with complete inline documentation. - -Each version module is authored against the latest patch release of its minor line: - -- `@openapi-spec/types/v3.0` — OpenAPI [3.0.4](https://spec.openapis.org/oas/v3.0.4.html) -- `@openapi-spec/types/v3.1` — OpenAPI [3.1.2](https://spec.openapis.org/oas/v3.1.2.html), reusing 3.0 types where unchanged -- `@openapi-spec/types/v3.2` — OpenAPI [3.2.0](https://spec.openapis.org/oas/v3.2.0.html), reusing 3.1 types where unchanged +

OpenAPI Spec

+ +
+ + codecov + + + weekly downloads + + + MIT License + + + Discord + + + Ask DeepWiki + +
+ +`@openapi-spec/types` provides TypeScript types for the [OpenAPI Specification](https://spec.openapis.org/), covering versions 3.0, 3.1, and 3.2. Every object and field is modelled after the specification, and every field carries the specification's own description as JSDoc with a link to its section, so the spec is readable from your editor. The package ships types only, no runtime code. + +Each version module targets the latest patch release of its minor line: + +| Module | Specification | Notes | +| -------------------------- | ---------------------------------------------------------- | ------------------------------------------------ | +| `@openapi-spec/types/v3.0` | [OpenAPI 3.0.4](https://spec.openapis.org/oas/v3.0.4.html) | | +| `@openapi-spec/types/v3.1` | [OpenAPI 3.1.2](https://spec.openapis.org/oas/v3.1.2.html) | Reuses 3.0 types for objects that did not change | +| `@openapi-spec/types/v3.2` | [OpenAPI 3.2.0](https://spec.openapis.org/oas/v3.2.0.html) | Reuses 3.1 types for objects that did not change | ## Usage ```ts -// Namespaces via the root export -import type { - OpenAPIV3_0, - OpenAPIV3_1, - OpenAPIV3_2, -} from '@openapi-spec/types' - -// or one version's module directly +// Every version as a namespace +import type { OpenAPIV3_0, OpenAPIV3_1, OpenAPIV3_2 } from '@openapi-spec/types' + +// Or one version directly import type { OpenAPIObject, SchemaObject } from '@openapi-spec/types/v3.1' -// SchemaObject accepts an optional data type for its data-carrying fields -// (`enum`, `default`, `example`, and in 3.1+ `const` and `examples`). +const doc: OpenAPIObject = { + openapi: '3.1.2', + info: { title: 'Pet Store', version: '1.0.0' }, + paths: {}, +} + +// SchemaObject takes an optional data type for its data-carrying fields: +// `enum`, `default`, `example`, and from 3.1 on `const` and `examples` const status = { type: 'string', enum: ['available', 'pending', 'sold'], @@ -30,7 +52,13 @@ const status = { } satisfies SchemaObject ``` -Type names follow the specification's section names (`InfoObject`, `PathItemObject`, `SchemaObject`, ...), and every field carries its specification description as JSDoc, linked back to the relevant spec section. +## Conventions + +- Type names follow the specification's section names: `InfoObject`, `PathItemObject`, `SchemaObject`, and so on. +- Fields the specification marks as deprecated carry an `@deprecated` tag. +- Rules the type system can express are enforced: allowed fields, value shapes, and version-specific literals such as `style` values. Rules it cannot express, like mutually exclusive fields or "at least one of", are stated in the JSDoc instead. + +The types are checked against the official example documents and the specification's own schema test corpus. See [tests/README.md](https://github.com/middleapi/openapi-spec/blob/main/packages/types/tests/README.md). ## Sponsors @@ -115,3 +143,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he With thanks to [36 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get openapi-spec here. + +## License + +Distributed under the MIT License. See [LICENSE](https://github.com/middleapi/openapi-spec/blob/main/LICENSE) for more information. diff --git a/packages/types/tests/README.md b/packages/types/tests/README.md index e6f538e..05402cd 100644 --- a/packages/types/tests/README.md +++ b/packages/types/tests/README.md @@ -1,13 +1,13 @@ # Real-document fixtures -Type-level fixtures generated from official OpenAPI documents. Each file embeds a complete document as an object literal typed as the `OpenAPIObject` of the version module matching its `openapi` field, so `tsc` at the repository root re-validates the whole corpus and rejects properties the specification does not allow. +Official OpenAPI documents embedded as TypeScript object literals. Each file types its document as the `OpenAPIObject` of the version module matching its `openapi` field, so `pnpm type:check` at the repository root compiles the whole corpus and fails whenever the types reject a valid document. The downgrader's corpus tests reuse the same fixtures as conversion input. Sources (Apache-2.0, © the OpenAPI Initiative): -- `examples/` — the official example documents from [OAI/learn.openapis.org](https://github.com/OAI/learn.openapis.org/tree/main/examples) (v3.0, v3.1, and v3.2 sets). -- `schema-tests-3.1/` — the `tests/schema/pass` documents from the [OAI/OpenAPI-Specification `v3.1-dev` branch](https://github.com/OAI/OpenAPI-Specification/tree/v3.1-dev/tests/schema/pass). -- `schema-tests-3.2/` — the `tests/schema/pass` documents from the [OAI/OpenAPI-Specification `v3.2-dev` branch](https://github.com/OAI/OpenAPI-Specification/tree/v3.2-dev/tests/schema/pass). +- `examples/`: the official example documents from [OAI/learn.openapis.org](https://github.com/OAI/learn.openapis.org/tree/main/examples), 3.0, 3.1, and 3.2 sets +- `schema-tests-3.1/`: the `tests/schema/pass` documents from the [OAI/OpenAPI-Specification `v3.1-dev` branch](https://github.com/OAI/OpenAPI-Specification/tree/v3.1-dev/tests/schema/pass) +- `schema-tests-3.2/`: the `tests/schema/pass` documents from the [OAI/OpenAPI-Specification `v3.2-dev` branch](https://github.com/OAI/OpenAPI-Specification/tree/v3.2-dev/tests/schema/pass) -The corresponding `tests/schema/fail` documents are intentionally not committed: most of them violate semantic rules that these types document rather than encode (mutual exclusions, at-least-one-of containers, per-location field applicability, non-empty arrays, map-key syntax). The ones that are type-expressible (unknown top-level fields, wrong value shapes, excess fields on Header/Link Objects, 3.2-only style values used in 3.1 documents) were verified to produce compile errors when this corpus was generated. +The matching `tests/schema/fail` documents are not committed. Most of them break semantic rules the types document rather than encode: mutual exclusions, at-least-one-of containers, per-location field applicability, non-empty arrays, and map-key syntax. The ones the types can catch (unknown top-level fields, wrong value shapes, excess fields on Header and Link Objects, 3.2-only `style` values in 3.1 documents) were verified to fail compilation when the corpus was generated. -The files are generated — do not edit them by hand; refresh them from the sources above instead. +The files are generated. Refresh them from the sources above instead of editing by hand.