Skip to content

Generate the JSON converter helpers with the emitter framework - #11602

Draft
Timothee Guerin (timotheeguerin) wants to merge 7 commits into
microsoft:mainfrom
timotheeguerin:hsc/json-converters-on-ef
Draft

Generate the JSON converter helpers with the emitter framework#11602
Timothee Guerin (timotheeguerin) wants to merge 7 commits into
microsoft:mainfrom
timotheeguerin:hsc/json-converters-on-ef

Conversation

@timotheeguerin

Copy link
Copy Markdown
Member

TimeSpanDurationConverter, Base64UrlJsonConverter and the two Unix epoch converters were emitted as raw string templates — no symbol resolution, no using management, hand-maintained indentation. They are now built from the framework's JsonConverter component, so the C# they reference is real symbols and Alloy owns the formatting.

This is the last of the stack, so it is also where the only output drift lands. Three files gain an explicit using System; (previously implicit via <ImplicitUsings>enable</ImplicitUsings>, so inert), and one method signature in UnixEpochDateTimeOffsetConverter.cs is wrapped by Alloy's printer:

-        public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        public override DateTimeOffset Read(
+            ref Utf8JsonReader reader,
+            Type typeToConvert,
+            JsonSerializerOptions options
+        )

Everything else in the snapshot is byte-identical.

Follow-up

The framework's createJsonConverterResolver is deliberately not adopted here. It keys converters by exact (type, encoding, encodeType), while this emitter switches on the std base scalar and ignores @encode entirely — so adopting it would change the wire format for specs using e.g. @encode(DurationKnownEncoding.seconds, int32). That is a real improvement (the emitter currently ignores that encoding) but it is a behavior change and belongs in its own PR with its own tests.


Final PR of a 7-PR stack moving @typespec/http-server-csharp onto the emitter framework. Stacked on #11601 — only the last commit is new here.

Adds handling for Tuple, StringTemplate, EnumMember, ModelProperty, UnionVariant,
template parameters and the full Intrinsic set. An unsupported type now reports a
diagnostic and falls back to `object` instead of throwing.

Also fixes the C# components reporting a TypeScript diagnostic for unsupported
scalars, and corrects the C# expressions emitted for the `null` and `never`
intrinsics. Adds an `isCSharpValueType` util.
…al_ComponentOverrides

The `declaration` descriptor existed but nothing dispatched to it, so an emitter
could override how a type is referenced but not how it is declared. The C#
`ClassDeclaration`, `Property` and `EnumDeclaration` now render through the
override point.
ClassDeclaration takes an explicit property list and extra members, Property
takes the full Alloy property prop set plus name/csharpType overrides,
EnumDeclaration takes an explicit member list and jsonAttributes, and
JsonConverter takes doc, access modifiers, extra members and an explicit
csharpType.
…xt.Json symbols

Deletes the emitter's own C# keyword table and its re-declaration of the
System.Text.Json.Serialization attributes, both of which are provided by
@alloy-js/csharp. Namespace segments colliding with BCL type names are still
renamed, now via a dedicated getCSharpNamespaceName helper.
…ource of truth

The emitter had three disagreeing scalar-to-C# name maps, so error model
constructors declared parameters such as DateOnly, Uri and sbyte while the
matching properties were DateTime, string and SByte - code that does not
compile. NumericConstraintAttribute<T> had the same mismatch.
…he emitter framework

Replaces the private forks of ClassDeclaration, Property and EnumDeclaration with
the framework components, expressing the emitter's own behavior as a declaration
override and component props. Generated output is unchanged.
…h the emitter framework

TimeSpanDurationConverter, Base64UrlJsonConverter and the Unix epoch converters
were raw string templates. Output is unchanged apart from an explicit
`using System;` that was previously implicit via ImplicitUsings.
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter-framework Issues for the emitter framework label Aug 7, 2026
@pkg-pr-new

pkg-pr-new Bot commented Aug 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/emitter-framework@11602
npm i https://pkg.pr.new/@typespec/http-server-csharp@11602

commit: 329edb2

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/emitter-framework
  • @typespec/http-server-csharp
Show changes

@typespec/emitter-framework - feature ✏️

Let emitters author the C# declaration components instead of forking them,> ,> - ClassDeclaration accepts an explicit properties list and extra members as children.,> - Property accepts every Alloy property prop, plus name and csharpType overrides.,> - EnumDeclaration accepts an explicit members list and a jsonAttributes prop.,> - JsonConverter accepts doc, access modifiers, extra members, an explicit csharpType, and a readReturns override.,> ,> tsx,> <ClassDeclaration type={model} properties={model.properties.values().filter(isVisible)} partial>,> <Constructor />,> </ClassDeclaration>,>

@typespec/emitter-framework - fix ✏️

Make the C# TypeExpression handle every type kind instead of throwing,> ,> Tuple, StringTemplate, EnumMember, ModelProperty, UnionVariant, template parameters and the full Intrinsic set are now supported, and an unsupported type reports a diagnostic and falls back to object rather than throwing. Also fixes the C# components reporting a TypeScript diagnostic for unsupported scalars, and corrects the C# expressions for the null and never intrinsics.

@typespec/emitter-framework - feature ✏️

Support declaration overrides in Experimental_ComponentOverrides,> ,> Only reference overrides were dispatched, so an emitter could customize how a type is referenced but not how it is declared, forcing it to fork the framework's declaration components. The C# ClassDeclaration, Property and EnumDeclaration now render through the override point.,> ,> tsx,> const overrides = Experimental_ComponentOverridesConfig().forTypeKind("ModelProperty", {,> declaration: (props) =>,> props.type.name === "id" ? (,> <props.Declaration {...props.declarationProps} name="Identifier" />,> ) : (,> props.default,> ),,> });,>

@typespec/http-server-csharp - internal ✏️

Use Alloy's C# keyword handling and System.Text.Json symbols instead of local copies,> ,> Deletes the emitter's own 217-line C# keyword table and its re-declaration of the System.Text.Json.Serialization attributes, which are both provided by @alloy-js/csharp. Namespace segments that collide with common BCL type names are still renamed, now in a dedicated getCSharpNamespaceName helper.

@typespec/http-server-csharp - internal ✏️

Generate the JSON converter helpers with the emitter framework's JsonConverter component,> ,> TimeSpanDurationConverter, Base64UrlJsonConverter and the Unix epoch converters were raw string templates. The generated classes are unchanged apart from an explicit using System; that was previously implicit.

@typespec/http-server-csharp - fix ✏️

Fix generated error model constructors and numeric constraint attributes using the wrong C# types,> ,> Error model constructors declared parameters such as DateOnly, Uri and sbyte while the matching properties were DateTime, string and SByte, producing code that did not compile. NumericConstraintAttribute<T> had the same mismatch, which stopped the converter from binding.

@typespec/http-server-csharp - internal ✏️

Build model, property and enum generation on @typespec/emitter-framework components,> ,> The emitter carried private forks of the framework's ClassDeclaration, Property and EnumDeclaration. They are now consumed directly, with the emitter's own behavior expressed as a declaration override and component props. Generated output is unchanged.

@azure-sdk-automation

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter-framework Issues for the emitter framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant