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.
Summary
In the 2020-12 dialect keywords beside a
$refapply conjunctively. Constraint keywords beside a$refare kept (minimum,maximum,pattern,minLength,maxLength,minProperties…), andso are the annotation keywords (
description,title,deprecated,examples,default,readOnly,x-*) and the validation-only ones (not). But five keywords that are neither reachthe IR in no form at all, with no
Unmodeledentry and no diagnostic:formatenumconstrequiredadditionalPropertiesThe node lowers to a bare alias
Scalarwhose only content isBasepointing at the referent. Thedeclaration 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
Compiling this reports zero diagnostics. The controls lower as expected —
PlainFmtgetsEncoding{name: email},PlainEnumanEnumwith two members,PlainConstaLiteral,PlainReqa closedModelwitharequired. EachRef*alias getsBaseand nothing else: noencoding, nomembers, no literal, noadditional, noconstraints, nounmodeled.The property position is identical — a property whose schema is
{$ref: '#/components/schemas/BaseStr', format: email, enum: [...], const: "aa"}keeps theconstraint siblings on the property and drops these five just as silently.
Why this is not one of the neighbouring issues
allOfbranch. Its fixdid not reach the plain alias position, and its reasoning ("a
$refbranch gets its own node")is about branches rather than about a component or property whose whole body is a
$ref.const→enum→allOf) whenthere is no
$ref.unhomedKeywords"only flagsformatwhen no type is declared beside it". In the alias case notypeis declared, so that guard should letformatthrough, and it does not.overwritten by another).
Expected
Per invariant 2, a keyword the alias lowering does not consume is kept verbatim under
Unmodeledwith 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
enumor aconstbeside a$refis anarrowing 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.