Skip to content

fix: skip null entries when mapping enums to OneOf validators - #15

Merged
hanneshayashi merged 1 commit into
mainfrom
hanneshayashi/nullable-enum-null-entry-is-emitted-as-0-in-gene
Oct 26, 2026
Merged

hanneshayashi merged 1 commit into
mainfrom
hanneshayashi/nullable-enum-null-entry-is-emitted-as-0-in-gene

Conversation

@hanneshayashi

Copy link
Copy Markdown
Collaborator

Closes #14

Problem

OpenAPI 3.0 only accepts null for a nullable: true enum if null is listed in the enum, so specs (and vacuum's nullable-enum-contains-null rule) list it:

public:
  type: string
  nullable: true
  enum: [editor, viewer, null]

GetStringValidators, GetIntegerValidators and GetFloatValidators decode each enum node into a Go value and only skip it when Decode returns an error. Decoding a YAML null returns no error and leaves the zero value, so the generated validator was stringvalidator.OneOf("editor", "viewer", "") (or 0 for integer/number enums). The downstream framework generator also appends the values to the description, which produced Possible values: `editor`, `viewer`, ``.

Solution

  • Skip enum nodes whose ShortTag() is !!null before decoding, in the string, int64 and float64 paths. A quoted "null" or "" is still a string and stays an allowed value.
  • An enum that only lists null now produces no validator, since the *ValidatorOneOf helpers already return nil for an empty slice.
  • Document the behavior in DESIGN.md.

Tests

  • TestGetStringValidators, TestGetIntegerValidators, TestGetFloatValidators: enum-with-null and enum-only-null cases. The string test also has enum-with-quoted-null-string. All of these fail without the fix.
  • Edgecase golden spec: new nullable_enum resource (OAS 3.1 type: [<t>, "null"]) with string, integer, double and null-only enums. It covers the real libopenapi parse path. Without the fix, TestGenerate_WithConfig/EdgeCase_API fails with ""/0 in all four validators. No other golden file changes.
  • Verified make generate in terraform-provider-doit with the spec from doiteng/omni#69368 (via a local replace). doit_sharing.public is back to OneOf("editor", "viewer") in the IR, sharing_resource_gen.go and docs/resources/sharing.md, and the rest of the generated output is unchanged. Provider make test and make lint pass.

A nullable enum lists null (OpenAPI 3.0 requires it for null to be valid),
but decoding a YAML null into a Go string, int64 or float64 returns no error
and leaves the zero value, so the generated OneOf validator accepted "" or 0.
Skip null nodes before decoding; an enum that only lists null now produces
no validator.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused fix consistently handles all three validator paths, includes unit and integration regression coverage, and has no identified blocking issues.

No open issues 🎉

What changed in this PR

Fixes #14 by preventing null enum entries from becoming unintended empty-string or zero values in generated Terraform OneOf validators.

Changes:

  • Filters null nodes before decoding string, integer, and float enums.
  • Adds unit and golden regression coverage for mixed and null-only enums, plus quoted "null" strings.
  • Documents that null-only enums produce no validator.
File Description
internal/​mapper/​oas/​string.go Skips null entries in string enums.
internal/​mapper/​oas/​string_test.go Covers mixed, null-only, and quoted-null string enums.
internal/​mapper/​oas/​number.go Skips null entries in float enums.
internal/​mapper/​oas/​number_test.go Covers mixed and null-only float enums.
internal/​mapper/​oas/​integer.go Skips null entries in integer enums.
internal/​mapper/​oas/​integer_test.go Covers mixed and null-only integer enums.
internal/​cmd/​testdata/​edgecase/​provider_code_spec.json Records expected validators without null-derived values.
internal/​cmd/​testdata/​edgecase/​openapi_spec.yml Adds nullable enum integration fixtures.
internal/​cmd/​testdata/​edgecase/​generator_config.yml Enables generation for the nullable enum fixture.
DESIGN.md Documents null enum mapping behavior.

Review effort: Balanced

@hanneshayashi
hanneshayashi merged commit 0c2adc2 into main Oct 26, 2026
6 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.

Nullable enum: null entry is emitted as "" / 0 in generated OneOf validator

2 participants