Skip to content

feat(Spec): add component:, one key field on every reusable attribute - #2219

Merged
DerManoMann merged 2 commits into
zircote:masterfrom
DerManoMann:feat/component-key
Sep 29, 2026
Merged

DerManoMann merged 2 commits into
zircote:masterfrom
DerManoMann:feat/component-key

Conversation

@DerManoMann

@DerManoMann DerManoMann commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

Overview

Each reusable spec attribute spelled its component key after its own type — schema:, response:, parameter:, header: and so on — and for four of them the same field was also the key the attribute nests under: response: 200 is a status code in an operation and a component name in components.responses, and header, link and example behave the same way. The object cannot tell which it holds, so isRoot() guessed from field presence, RequestBody, Response, Parameter and Link each drew the key-plus-ref line differently, and a response that failed to nest became a component named 200 with nothing said until Cleanup noticed.

One field, component, names the key a reusable attribute is filed under, on every type — including PathItem and MediaType, which had no key at all and could not be reused. The value fields keep their value, the identity has its own field, and the root rule is one rule: keyed means root, and key-plus-ref is either a nested reference or an aliasing component.

The historic spellings keep working through 8.0 and produce the same document — every fixture and example moved to the new spelling with its expected output unchanged — and trigger a deprecation once. Only their use as a component key is deprecated; response: 404 on a nested response or header: 'X-Rate-Limit' on a header inside one is the nesting key and stays. Classic is untouched and reports nothing — the bridge maps its keys to component directly — but the classic → spec migration is now a key rename as well as a change of namespace, so it is no longer the one use line per file the migration path promised.

Changes

  • component: on Schema, Response, Parameter, RequestBody, Header, Link, Example, Security\Scheme, PathItem and MediaType
  • ComponentName::of() answers with component; ComponentName::normalise() fills it from the historic spellings once per build, before the resolver's first index
  • isRoot() follows component on the conditionally-root types; a keyed Header or Example stands alone without Components
  • PathItem with a key is a components.pathItems entry and governs no class; 3.0 reports and omits it
  • MediaType with a key is a components.mediaTypes entry from 3.2; earlier versions report and omit it
  • compilePathItem() emits $ref
  • a schema's title is no longer a key fallback; a keyless schema is reported
  • the historic spellings marked @deprecated, removed in 8.0, with a runtime deprecation; ROADMAP.md lists them
  • Augmenter\Names, Enums, Refs, Inheritance\Schemas and the compiler diagnostics read component
  • HybridBridge passes component directly, so classic input never reports
  • fixtures and examples on the new spelling; ComponentNameTest and ReusableComponentsTest added
  • docs/dev/pipeline.md root taxonomy and the guide's Components section rewritten; reference/spec-attributes.md regenerated
  • docs/guide/modes.md migration path names the four classic spellings that become component:, and its v8 line is scoped the way ROADMAP.md scopes it — one use line per file for code already on OpenApi\Spec, plus the component keys coming from classic; the guide's deprecation warning states that classic reports nothing

- `component` on the ten reusable Spec types; the historic key fields alias
  onto it — in the constructor where the field can only be the key, and in
  `ComponentName::normalise()` where it is also a nesting key
- `ComponentName::of()` reads `component`; `isRoot()` follows it on the
  conditionally-root types
- `PathItem` and `MediaType` gain the field and their `components` buckets;
  `compilePathItem()` emits `$ref`
- a schema's title is no longer a key fallback
- historic spellings `@deprecated`, removed in 8.0, with a runtime deprecation
- fixtures, examples and docs on the new spelling; reference regenerated
…th Spec

The Components rewrite described the new key from inside `Spec`: "before 6.11
each type spelled its key after itself". Those spellings -- `schema`,
`parameter`, `request`, `securityScheme` -- are also classic's, current and
not deprecated, so a classic reader met their own field names under a
deprecation notice with nothing saying classic is untouched. It is: the
bridge maps them to `component` directly and `ComponentName::normalise()`
only reports for specifications the user wrote.

The migration path said the opposite of what now happens. Step 2 offered
`OpenApi\Spec` as a change of namespace, and the v8 line priced the move at
"one `use` line per file" -- the ROADMAP sentence with its scoping clause
dropped. Coming from classic it is that plus every component key.

- modes.md step 2 names the four classic spellings that become `component:`
- modes.md v8 line scoped the way `ROADMAP.md` scopes it, with the classic
  case spelled out
- the guide's deprecation warning states that classic reports nothing, and
  where the cost actually lands

Spec is still beta, so the deprecation inside it is the smaller half of this.
@DerManoMann
DerManoMann merged commit 26540b8 into zircote:master Sep 29, 2026
19 checks passed
@DerManoMann
DerManoMann deleted the feat/component-key branch September 29, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant