Skip to content

fix: quote non-identifier dart_mappable enum values for nullable/list types#468

Open
RootSoft wants to merge 1 commit into
Carapacik:mainfrom
RootSoft:fix/mappable-enum-value-quoting
Open

fix: quote non-identifier dart_mappable enum values for nullable/list types#468
RootSoft wants to merge 1 commit into
Carapacik:mainfrom
RootSoft:fix/mappable-enum-value-quoting

Conversation

@RootSoft

@RootSoft RootSoft commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This PR fixes enum generation for dart_mappable when an enum's schema uses a JSON Schema type list such as ["string", "null"] (common in OpenAPI 3.1 specs, e.g. those generated from Laravel form request rules).

Problem

Generated dart_mappable enums were emitting the JSON value as a bare identifier instead of a string literal:

@MappableValue(hidden_gem)
hiddenGem,

@MappableValue(price_asc)
priceAsc,

@MappableValue(...) requires a constant expression, so an unquoted identifier like hidden_gem or price_asc is not valid Dart. The generated file fails to compile with:

Arguments of a constant creation must be constant expressions.

This only happened for enum values that are not valid Dart identifiers (contain underscores, dashes, digits, etc.) when the enum type was declared as a nullable/list type.

Root cause

The dart_mappable enum template only wrapped values in quotes when the enum's parsed type was exactly 'string':

@MappableValue(${type == 'string' ? "'$protectedJsonKey'" : protectedJsonKey})

When a schema declares:

"sort": {
  "type": ["string", "null"],
  "enum": ["rating", "name", "price_asc", "price_desc"]
}

the parser stores the enum type as the literal string "[string, null]" — not "string". (This is intentional: the nullability is preserved in the type string so toDartType() can derive String? for the JSON field.) Because "[string, null]" != "string", the condition was false and the value was emitted unquoted.

The freezed / json_serializable template already handled this correctly by falling back to quoting any non-numeric value. The dart_mappable template was missing that fallback.

Example

This schema:

"sort": {
  "type": ["string", "null"],
  "enum": ["rating", "name", "price_asc", "price_desc"]
}

previously generated (invalid):

@MappableEnum(defaultValue: Sort2.unknown)
enum Sort2 {
  @MappableValue(rating)
  rating,
  @MappableValue(name)
  name,
  @MappableValue(price_asc)
  priceAsc,
  @MappableValue(price_desc)
  priceDesc,
  @MappableValue(unknown)
  unknown;
  ...
}

Fix

The value-literal logic is now shared between the freezed and dart_mappable templates via a single helper. It quotes strings and any non-numeric value, leaves numeric values bare, and keeps null as null:

@MappableEnum(defaultValue: Sort2.unknown)
enum Sort2 {
  @MappableValue('rating')
  rating,
  @MappableValue('name')
  name,
  @MappableValue('price_asc')
  priceAsc,
  @MappableValue('price_desc')
  priceDesc,
  @MappableValue('unknown')
  unknown;
  ...
}

Behavior after the fix:

  • String / non-identifier values → quoted: @MappableValue('price_asc'), @MappableValue('hidden_gem')
  • Numeric enum values → bare: @MappableValue(0), @MappableValue(-1)
  • Null values → @MappableValue(null)

This restores valid, compilable dart_mappable output for enums declared with nullable/list types.

Tests

Added a new e2e test enum_types_list_mappable (a dart_mappable variant of the existing enum_types_list fixture) that covers ["string", "null"], ["string", "integer"], and enum properties nested inside objects. The full e2e suite and generator/parser unit tests pass.

@RootSoft RootSoft changed the title enum value tests fix: quote non-identifier dart_mappable enum values for nullable/list types Jul 1, 2026
@Carapacik Carapacik self-requested a review July 5, 2026 22:05
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