Skip to content

openapi: format/enum/const/required/additionalProperties beside a $ref vanish #283

Description

@OmarAlJarrah

Summary

In the 2020-12 dialect keywords beside a $ref apply conjunctively. Constraint keywords beside a
$ref are kept (minimum, maximum, pattern, minLength, maxLength, minProperties …), and
so are the annotation keywords (description, title, deprecated, examples, default,
readOnly, x-*) and the validation-only ones (not). But five keywords that are neither reach
the IR in no form at all, with no Unmodeled entry and no diagnostic:

  • format
  • enum
  • const
  • required
  • additionalProperties

The node lowers to a bare alias Scalar whose only content is Base pointing at the referent. The
declaration is gone.

Both positions behave the same way, so this is the alias lowering rather than one carrier: a
component whose body is $ref + siblings, and a property whose schema is $ref + siblings.

Reproduction

openapi: 3.1.0
info: {title: T, version: "1.0.0"}
paths: {}
components:
  schemas:
    BaseStr: {type: string}
    BaseObj: {type: object, properties: {a: {type: string}}}

    # Controls — the same keywords with no $ref beside them.
    PlainFmt:   {type: string, format: email}
    PlainEnum:  {type: string, enum: ["aa", "aaa"]}
    PlainConst: {type: string, const: "aa"}
    PlainReq:   {type: object, properties: {a: {type: string}}, required: [a], additionalProperties: false}

    # Beside a $ref.
    RefFmt:   {$ref: '#/components/schemas/BaseStr', format: email}
    RefEnum:  {$ref: '#/components/schemas/BaseStr', enum: ["aa", "aaa"]}
    RefConst: {$ref: '#/components/schemas/BaseStr', const: "aa"}
    RefShape: {$ref: '#/components/schemas/BaseObj', required: [a], additionalProperties: false}

Compiling this reports zero diagnostics. The controls lower as expected — PlainFmt gets
Encoding{name: email}, PlainEnum an Enum with two members, PlainConst a Literal,
PlainReq a closed Model with a required. Each Ref* alias gets Base and nothing else: no
encoding, no members, no literal, no additional, no constraints, no unmodeled.

The property position is identical — a property whose schema is
{$ref: '#/components/schemas/BaseStr', format: email, enum: [...], const: "aa"} keeps the
constraint siblings on the property and drops these five just as silently.

Why this is not one of the neighbouring issues

Expected

Per invariant 2, a keyword the alias lowering does not consume is kept verbatim under Unmodeled
with a diagnostic naming it, the way the constraint and annotation siblings at the same position
already are. Silence is what makes this one costly: an enum or a const beside a $ref is a
narrowing idiom, so the generated SDK admits values the source forbids and nothing says so.

Found while reviewing #272, which covers a different set of drops in the operation walk and does
not touch the schema alias lowering.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions