fix: honor @encodedName on enum members - #11980
Open
Zach Bimson (bimsonz) wants to merge 1 commit into
Open
Zach Bimson (bimsonz) wants to merge 1 commit into
Zach Bimson (bimsonz) wants to merge 1 commit into
Conversation
@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: 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. |
Contributor
There was a problem hiding this comment.
🟡 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 existingresolveEncodedNamecases 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
Atomto 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 insrc/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 useresolveEncodedEnumMemberValue.
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.valueinpackages/openapi3/src/openapi.ts:491-495before 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; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the enum half of #2954. Union variants are not included, per the triage comment.
@encodedNameon 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.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/jsonis resolved, as OpenAPI cannot express a different enum value per media type.Changes
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 andMEMBER: 0still resolves to0. Used for example values, default values and discriminator values. Adds agetDiscriminatedUnionFromInheritance(program, type, discriminator)overload and deprecates(type, discriminator), asgetDiscriminatedUniondid in Discriminated union v2 #6059.JsonStringEnumMemberName.ValueExpressionorAtomnow needs aTspContext.Encoded name conflict validation is unchanged.
Compatibility
Marked
breakingfor the compiler. Output changes for any spec that already carries@encodedNameon an enum member, and such a spec can now reportinvalid-discriminated-union-variantorinvalid-discriminator-valueif 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 withenum-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@encodedNameon an enum member.Testing
pnpm test,lint:ci,format:check,cspell,chronus verifytsp-integration azure-specs,typespec-next): 585/585 pass, same asmaincoreat this commit:build,testandtest:e2epass