Skip to content

fix(generator): treat string const as single-value enum (closes #10)#12

Merged
lightsofapollo merged 2 commits into
mainfrom
fix/issue-10-const-only-property
May 7, 2026
Merged

fix(generator): treat string const as single-value enum (closes #10)#12
lightsofapollo merged 2 commits into
mainfrom
fix/issue-10-const-only-property

Conversation

@lightsofapollo
Copy link
Copy Markdown
Contributor

Summary

  • Treat { "type": "string", "const": "X" } (no enum array) as a degenerate single-value enum so the generator emits a tightly-typed single-variant enum instead of Option<String>.
  • Centralized in SchemaDetails::is_string_enum / string_enum_values so all four call sites (typed-string, untyped-string, property-with-context, inferred-string) pick up the change.

Before / After

For the spec from #10:

"ConstModifier": {
  "type": "object",
  "properties": {
    "someConstant": { "type": "string", "const": "TheOnlyValidValue" }
  }
}

Before:

pub struct ConstModifier {
    #[serde(rename = "someConstant", skip_serializing_if = "Option::is_none")]
    pub some_constant: Option<String>,
}

After:

pub struct ConstModifier {
    #[serde(rename = "someConstant", skip_serializing_if = "Option::is_none")]
    pub some_constant: Option<ConstModifierSomeConstant>,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Default)]
pub enum ConstModifierSomeConstant {
    #[default]
    #[serde(rename = "TheOnlyValidValue")]
    TheOnlyValidValue,
}

Construction:

let m = ConstModifier {
    some_constant: Some(ConstModifierSomeConstant::TheOnlyValidValue),
};
// or simply: ConstModifier::default()

Discriminator paths are unaffected

  • extract_inline_discriminator_value (src/analysis.rs:2507) reads const_value directly when picking variant tags.
  • The variant struct's discriminator field is filtered out of the generated struct in src/generator.rs:932-947, so this change does not affect (de)serialization of tagged unions.

Snapshot drift

Three pre-existing snapshots are updated, all in the desired direction (bare String → single-variant enum on standalone structs):

  • debug_test.snap
  • type_property_only_test.snap
  • oneof_in_property.snap (ImageBlock.type field — ImageBlock itself is not a discriminated-union variant)
  • array_union_items.snap

The oneof_in_property and array_union_items snapshots also pick up some orphan single-variant enums (e.g., URLImageSourceType, Base64ImageSourceType) for discriminator fields whose enums are no longer referenced by their parent struct. This is a pre-existing behavior — visible today in discriminator_no_mapping.snap (DogSpecies / CatSpecies) for any enum: ["X"] discriminator field. Tracked separately in #11; intentionally out of scope here.

Test plan

  • New test tests/const_only_property_test.rs reproducing Overly Broad Type Generated When Using "const" #10 (both required and optional cases) — both pass.
  • Full cargo test suite — all green.
  • cargo fmt — clean.
  • Reviewed all snapshot diffs — only intended changes, no regressions.

🤖 Generated with Claude Code

lightsofapollo and others added 2 commits May 7, 2026 17:42
A property like `{ "type": "string", "const": "X" }` previously generated
`Option<String>`, leaving the generated client able to send any string
value. Treat it as a degenerate single-value enum so the generator emits
a tightly-typed single-variant enum, matching how `enum: ["X"]` is
already handled.

Centralized in `SchemaDetails::is_string_enum` / `string_enum_values` so
all four call sites (typed-string, untyped-string, property-with-context,
inferred-string) pick up the change consistently.

Discriminator paths are unaffected: `extract_inline_discriminator_value`
reads `const_value` directly, and the variant struct's discriminator
field is filtered out of the generated struct (`generator.rs:932-947`).

Note: the existing orphan-enum pattern (e.g. `DogSpecies` in
`discriminator_no_mapping.snap`) becomes more visible because more
discriminator fields now produce single-variant enums. Tracked
separately in #11.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generated code for properties with a string `const` (no `enum` array)
changes from `Option<String>` to `Option<<Struct><Prop>>` enum, which
is a breaking change for downstream consumers constructing those types.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lightsofapollo lightsofapollo merged commit 3e93ad3 into main May 7, 2026
4 checks passed
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