Skip to content

fix: honor @encodedName on enum members - #11980

Open
Zach Bimson (bimsonz) wants to merge 1 commit into
microsoft:mainfrom
bimsonz:encoded-name-enum-members
Open

Zach Bimson (bimsonz) wants to merge 1 commit into
microsoft:mainfrom
bimsonz:encoded-name-enum-members

Conversation

@bimsonz

Copy link
Copy Markdown

Fixes the enum half of #2954. Union variants are not included, per the triage comment.

@encodedName on an enum member was accepted but ignored. It now sets the value the member is serialized as. Without it, a member is serialized as its explicit value, or as its name when it has none.

enum ConversationStatus {
  // Keeps 0 for protobuf, serialized as "unknown" in JSON
  @encodedName("application/json", "unknown")
  CONVERSATION_STATUS_UNSPECIFIED: 0,

  @encodedName("application/json", "ready")
  CONVERSATION_STATUS_READY: 1,
}

This is what a dual protobuf and JSON surface needs: protobuf requires integer values, and JSON wants strings. Overriding the name alone does not cover it, since the value always wins.

Only application/json is resolved, as OpenAPI cannot express a different enum value per media type.

Changes

  • compiler: adds resolveEncodedEnumMemberValue(program, member, mimeType), which returns the encoded name if one is declared, else the member value, else the name. It reads the decorator state, so a declared override is distinguishable from an absent one and MEMBER: 0 still resolves to 0. Used for example values, default values and discriminator values. Adds a getDiscriminatedUnionFromInheritance(program, type, discriminator) overload and deprecates (type, discriminator), as getDiscriminatedUnion did in Discriminated union v2 #6059.
  • openapi3, json-schema: enum schemas, member references and discriminator mappings. An encoded integer member is emitted as a string.
  • http-server-js: generated enum values, member literal types and union variant differentiation.
  • http-server-csharp: JsonStringEnumMemberName.
  • emitter-framework: TS enum declarations, union and value expressions, and Python atoms, so enum values match the discriminator keys from the typekit. Rendering an enum value with ValueExpression or Atom now needs a TspContext.

Encoded name conflict validation is unchanged.

Compatibility

Marked breaking for the compiler. Output changes for any spec that already carries @encodedName on an enum member, and such a spec can now report invalid-discriminated-union-variant or invalid-discriminator-value if the member is used as a discriminator value. An encoded name is a string, so encoding only some members of an integer enum gives a mixed-type enum, which OpenAPI 3.0 rejects with enum-unique-type.

TCGC computes enum values as value ?? name, so clients generated through it keep the member value until it is updated. No project in azure-rest-api-specs uses @encodedName on an enum member.

Testing

  • pnpm test, lint:ci, format:check, cspell, chronus verify
  • azure-rest-api-specs (tsp-integration azure-specs, typespec-next): 585/585 pass, same as main
  • Azure/typespec-azure with core at this commit: build, test and test:e2e pass

@Encodedname now sets the value an enum member is serialized as, so an enum can
keep the values another protocol requires and present different values in json.
Applied by the compiler (example, default and discriminator values), openapi3,
json-schema, http-server-js, http-server-csharp and emitter-framework through
the new resolveEncodedEnumMemberValue helper.

getDiscriminatedUnionFromInheritance gets a program-first overload so enum
member discriminator values can resolve their encoded value; the previous
signature is deprecated.
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@microsoft-github-policy-service microsoft-github-policy-service Bot added compiler:core Issues for @typespec/compiler emitter-framework Issues for the emitter framework meta:website TypeSpec.io updates emitter:json-schema labels Sep 16, 2026
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:openapi3 Issues for @typespec/openapi3 emitter label Sep 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved critical C# escaping and moderate Python/OpenAPI issues require fixes.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Updates enum serialization so @encodedName("application/json", ...) controls JSON values across compiler, schema, server, and emitter-framework outputs.

Changes:

  • Adds encoded enum value resolution with explicit-value and zero-value handling.
  • Updates OpenAPI, JSON Schema, JavaScript, C#, TypeScript, and Python emission.
  • Adds discriminator support, documentation, tests, and changelog entries.
File summaries
File Summary
website/src/content/docs/docs/standard-library/encoded-names.md Documents encoded enum values and resolver usage.
packages/openapi3/test/xml-models.test.ts Verifies unrelated @name behavior remains unchanged.
packages/openapi3/test/union-schema.test.ts Tests encoded enum discriminator mappings.
packages/openapi3/test/enums.test.ts Tests encoded values, defaults, references, and mixed types.
packages/openapi3/test/discriminator.test.ts Tests encoded enum inheritance discriminators.
packages/openapi3/src/schema-emitter.ts Resolves encoded values for references and discriminators.
packages/openapi3/src/schema-emitter-3-1.ts Emits encoded values in OpenAPI 3.1 schemas.
packages/openapi3/src/schema-emitter-3-0.ts Emits encoded values and mixed-type diagnostics. Moderate (1 vote): server-variable validation still checks raw numeric values.
packages/json-schema/test/enums.test.ts Tests encoded enum schemas and defaults.
packages/json-schema/test/discriminator.test.ts Tests encoded discriminator values.
packages/json-schema/src/json-schema-emitter.ts Applies encoded values to schemas, references, and discriminators.
packages/http-server-js/vitest.config.ts Increases test timeout.
packages/http-server-js/test/tester.ts Centralizes the HTTP server test harness.
packages/http-server-js/test/scalar.test.ts Uses the shared test harness.
packages/http-server-js/test/enum.test.ts Tests generated encoded values and union differentiation.
packages/http-server-js/src/util/differentiate.ts Uses encoded values during differentiation.
packages/http-server-js/src/common/reference.ts Emits encoded enum member literals.
packages/http-server-js/src/common/enum.ts Emits encoded enum declarations.
packages/http-server-csharp/test/emitter.test.ts Tests generated C# enum serialization attributes.
packages/http-server-csharp/src/components/enums/enums.tsx Applies encoded values to C# enum members. Critical (2 votes): encoded strings are not escaped before attribute generation.
packages/emitter-framework/test/typescript/components/value-expression.test.tsx Tests encoded enum value expressions.
packages/emitter-framework/test/typescript/components/type-transform.test.tsx Tests consistency with discriminator checks.
packages/emitter-framework/test/typescript/components/enum-declaration.test.tsx Tests encoded TypeScript enum declarations.
packages/emitter-framework/src/typescript/components/value-expression.tsx Resolves encoded enum values.
packages/emitter-framework/src/typescript/components/union/expression.tsx Resolves encoded union expressions.
packages/emitter-framework/src/typescript/components/union/expression.test.tsx Tests encoded union expressions.
packages/emitter-framework/src/typescript/components/enum-declaration.tsx Emits encoded TypeScript enum members.
packages/emitter-framework/src/python/components/atom/atom.tsx Resolves encoded Python atom values. Moderate (1 vote): Python enum declarations still use raw member values.
packages/emitter-framework/src/python/components/atom/atom.test.tsx Tests encoded Python enum atoms.
packages/compiler/test/typekit/model.test.ts Tests encoded TypeKit discriminator values.
packages/compiler/test/helpers/discriminator-utils.test.ts Tests program-aware and deprecated discriminator APIs.
packages/compiler/test/decorators/examples.test.ts Tests encoded enum example serialization.
packages/compiler/test/decorators/decorators.test.ts Tests encoded enum decorator resolution and validation.
packages/compiler/src/typekit/kits/model.ts Passes the program to inheritance discriminator resolution.
packages/compiler/src/lib/examples.ts Serializes enum examples using encoded values.
packages/compiler/src/lib/encoded-names.ts Adds the encoded enum value resolver. Nit (1 vote): add direct coverage for MIME fallback and explicit-value/zero precedence.
packages/compiler/src/lib/decorators.ts Exports the new resolver.
packages/compiler/src/index.ts Exposes the resolver and discriminator API.
packages/compiler/src/core/helpers/index.ts Exports the compatibility overload.
packages/compiler/src/core/helpers/discriminator-utils.ts Resolves encoded discriminator values.
.chronus/changes/encoded-name-enum-members-openapi3-2026-9-15-19-0-2.md Records the OpenAPI change.
.chronus/changes/encoded-name-enum-members-json-schema-2026-9-15-19-0-3.md Records the JSON Schema change.
.chronus/changes/encoded-name-enum-members-http-server-js-2026-9-15-19-0-4.md Records the JavaScript server change.
.chronus/changes/encoded-name-enum-members-http-server-csharp-2026-9-15-19-0-5.md Records the C# server change.
.chronus/changes/encoded-name-enum-members-emitter-framework-2026-9-15-19-0-7.md Records emitter-framework changes.
.chronus/changes/encoded-name-enum-members-compiler-2026-9-15-19-0-1.md Records compiler behavior changes.
.chronus/changes/encoded-name-discriminator-program-compiler-2026-9-15-19-0-6.md Records the deprecated discriminator overload.
Review details

Suppressed comments (3)

packages/compiler/src/lib/encoded-names.ts:112

  • This is a new root-exported compiler helper, but the compiler tests only exercise it indirectly through emitters and serializeValueAsJson. Add a direct test beside the existing resolveEncodedName cases to lock down the public API's MIME fallback and explicit-value/zero precedence.
export function resolveEncodedEnumMemberValue(
  program: Program,
  member: EnumMember,
  mimeType: string,
): string | number {
  return getEncodedName(program, member, mimeType) ?? member.value ?? member.name;

packages/emitter-framework/src/python/components/atom/atom.tsx:76

  • By changing Atom to emit the resolved JSON value, this makes enum values and defaults render as the encoded string, but Python enum declarations still use the raw member value in src/python/components/enum-declaration/enum-member.tsx; an encoded member without a value remains auto-valued (and an encoded numeric member remains numeric). Generated enum constants therefore no longer agree with the literals produced here, so the Python enum declaration and its type detection must also use resolveEncodedEnumMemberValue.
          jsValue={resolveEncodedEnumMemberValue($.program, props.value.value, "application/json")}

packages/openapi3/src/schema-emitter-3-0.ts:129

  • This now emits an encoded numeric enum member as a string, but OpenAPI server-variable validation still rejects any truthy numeric member.value in packages/openapi3/src/openapi.ts:491-495 before this schema is used. Consequently an all-encoded integer enum is still rejected as a server variable even though its emitted enum/default values are strings; validate the resolved JSON member values instead.
  • Files reviewed: 47/47 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +55 to +56
const value = resolveEncodedEnumMemberValue(program, member, "application/json");
return typeof value === "string" ? value : key;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compiler:core Issues for @typespec/compiler emitter:json-schema emitter:openapi3 Issues for @typespec/openapi3 emitter emitter-framework Issues for the emitter framework meta:website TypeSpec.io updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants