Skip to content

Preserve definition-level defaults when types are reached via $ref#1042

Open
danieleades wants to merge 1 commit into
oxidecomputer:mainfrom
danieleades:fix/ref-definition-default
Open

Preserve definition-level defaults when types are reached via $ref#1042
danieleades wants to merge 1 commit into
oxidecomputer:mainfrom
danieleades:fix/ref-definition-default

Conversation

@danieleades

Copy link
Copy Markdown
Contributor

Bug

When a schema definition carries its own default value, that default is dropped when the type is reached via $ref. For example:

{
  "definitions": {
    "DefaultedStruct": {
      "type": "object",
      "properties": { "a": { "type": "string" } },
      "default": { "a": "hello" }
    }
  }
}

Referenced via "$ref": "#/definitions/DefaultedStruct", the generated type loses the definition-level default (its Default impl falls back to per-field defaults, yielding a: None). Inlining the identical schema preserves it (a: Some("hello")).

Cause

convert_ref_type recomputes the default from the metadata returned by convert_schema and assigns it unconditionally. For struct conversions that returned metadata is NoneTypeEntryStruct::from_metadata consumes the metadata and records the default itself — so the already-recorded default was clobbered with None. (Enums were unaffected because convert_enum_string returns Some(metadata), which is why the asymmetry went unnoticed.)

Fix

Only override the recorded default when the metadata returned by the conversion actually specifies one.

Precedence is preserved: a default declared at the reference site (sibling metadata alongside $ref, handled by the merge path) comes back as Some and still takes precedence over the definition-level default.

Testing

New golden test typify/tests/schemas/ref-with-default.json covering:

  • a definition-level struct default reached via $ref — now generates Default for DefaultedStruct with a: Some("hello");
  • a definition-level enum default reached via $ref — unchanged behavior;
  • a ref-site override (allOf + sibling default) — still wins over the definition-level default.

No other golden outputs change. cargo test --workspace --locked passes; cargo fmt --all -- --check is clean.

When a schema definition carries its own `default` value, that default
was dropped when the type was converted via a reference:
convert_ref_type recomputed the default from the metadata returned by
convert_schema — which is `None` for struct conversions, since
TypeEntryStruct::from_metadata consumes the metadata and records the
default itself — and unconditionally assigned it, clobbering the
already-recorded default. As a result the generated type lacked its
`Default` impl (and default-dependent codegen) even though the same
schema, inlined, produced one.

Only override the recorded default when the metadata returned by the
conversion actually specifies one. This preserves the existing
precedence: a default declared at the reference site (merged sibling
metadata alongside $ref) still comes back as `Some` and takes
precedence over the definition-level default.

Adds a golden test covering a definition-level default reached via
$ref (struct and enum) and a ref-site override.
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