Skip to content

Dispatch declaration overrides in Experimental_ComponentOverrides - #11597

Merged
iscai-msft merged 1 commit into
microsoft:mainfrom
timotheeguerin:ef/declaration-overrides
Aug 28, 2026
Merged

iscai-msft merged 1 commit into
microsoft:mainfrom
timotheeguerin:ef/declaration-overrides

Conversation

@timotheeguerin

@timotheeguerin Timothee Guerin (timotheeguerin) commented Aug 7, 2026

Copy link
Copy Markdown
Member

An override descriptor already accepted a declaration entry, but nothing ever dispatched to it — only reference was wired up. So an emitter could change how a type is referenced and had no say in how it is declared. The only way to customize a declaration was to copy the framework component into your own package and diverge from it, which is exactly what @typespec/http-server-csharp did for classes, properties and enums.

Experimental_OverridableComponent now dispatches declaration too, and the C# ClassDeclaration, Property and EnumDeclaration render through it. An override can replace the declaration outright, or re-render the default with different props:

const overrides = Experimental_ComponentOverridesConfig().forTypeKind("ModelProperty", {
  declaration: (props) =>
    isSecret(props.type) ? (
      <props.Declaration {...props.declarationProps} public={false} internal />
    ) : (
      props.default
    ),
});

props.Declaration is the unwrapped body, so re-rendering it does not recurse back through the override.

The declaration props type is generic and defaults to Record<string, any>, because the existing Experimental_CustomTypeToProps map is TypeScript-specific (VarDeclarationProps, ObjectPropertyProps) and means nothing for C#. Callers that want type safety pass the concrete props type: .forTypeKind<"ModelProperty", PropertyProps>(...).


Independent — targets main and can merge on its own.

One of 7 PRs moving @typespec/http-server-csharp onto the emitter framework instead of its private forks: #11596, #11597, #11598, #11599, #11600, #11601, #11602.

@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@11597

commit: b10f5fb

@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter-framework Issues for the emitter framework label Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/emitter-framework
Show changes

@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.,> ,> Override precedence is resolved per override kind, so a type-level override that only defines reference does not shadow a kind-level declaration override, and vice versa.,> ,> tsx,> const overrides = Experimental_ComponentOverridesConfig().forTypeKind("ModelProperty", {,> declaration: (props) =>,> props.type.name === "id" ? (,> <props.Declaration {...props.declarationProps} name="Identifier" />,> ) : (,> props.default,> ),,> });,>

@azure-sdk-automation

azure-sdk-automation Bot commented Aug 7, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

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.

Pull request overview

This PR extends Experimental_ComponentOverrides so emitters can override declarations (not just references), and wires the C# declaration components (ClassDeclaration, Property, EnumDeclaration) through the overridable dispatch point. This unblocks customizing how types are declared without forking framework components, supporting the ongoing migration of @typespec/http-server-csharp onto the emitter framework.

Changes:

  • Add declaration-override typing + dispatch support to Experimental_OverridableComponent and override config generics.
  • Wrap C# ClassDeclaration, Property, and EnumDeclaration render paths with Experimental_OverridableComponent in declaration mode.
  • Add C# tests covering declaration override behavior and add a Chronus changelog entry.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/emitter-framework/src/csharp/components/property/property.tsx Routes property declarations through the overridable declaration dispatch.
packages/emitter-framework/src/csharp/components/enum/declaration.tsx Routes enum declarations through the overridable declaration dispatch.
packages/emitter-framework/src/csharp/components/class/declaration.tsx Routes class declarations through the overridable declaration dispatch.
packages/emitter-framework/src/csharp/components/class/declaration.test.tsx Adds tests validating declaration overrides for class/property/enum declarations.
packages/emitter-framework/src/core/components/overrides/config.ts Extends overrides config APIs to carry a generic declaration-props type parameter.
packages/emitter-framework/src/core/components/overrides/component-overrides.tsx Adds declaration override types and dispatch logic to Experimental_OverridableComponent.
.chronus/changes/ef-declaration-overrides-2026-8-5.md Changelog entry for declaration override support.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/emitter-framework/src/core/components/overrides/component-overrides.tsx Outdated
…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.

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

@iscai-msft
iscai-msft added this pull request to the merge queue Aug 28, 2026
Merged via the queue into microsoft:main with commit 3fd3099 Aug 28, 2026
33 checks passed
Timothee Guerin (timotheeguerin) added a commit to timotheeguerin/typespec that referenced this pull request Aug 28, 2026
The emitter carried a 217-line hand-maintained table of C# keywords and
a `createLibrary` call re-declaring the `System.Text.Json.Serialization`
attributes. `@alloy-js/csharp` ships both, and its versions are better:
the local keyword list was missing `delegate`, and hand-declared symbols
do not participate in Alloy's automatic `using` management.

Both are deleted in favour of the Alloy equivalents
(`isValidCSharpIdentifier`, `csharpKeywords`, the `System/Text/Json`
builtins), along with the local `getDocComments` copy, which is already
exported from `@typespec/emitter-framework/csharp`.

One thing Alloy deliberately does *not* do is worth calling out: its
name policy `@`-escapes real keywords, but the emitter needs namespace
segments colliding with common BCL type names to be **renamed** — a
namespace called `Type` shadows `System.Type` and breaks every
`typeof()` in the generated converters. That rule survives, now isolated
in `getCSharpNamespaceName` and built on Alloy's keyword sets rather
than a parallel list.

Generated output is unchanged.

---

Independent — targets `main` and can merge on its own.

One of 7 PRs moving `@typespec/http-server-csharp` onto the emitter
framework instead of its private forks: microsoft#11596, microsoft#11597, microsoft#11598, microsoft#11599,
microsoft#11600, microsoft#11601, microsoft#11602.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Timothee Guerin (timotheeguerin) added a commit to timotheeguerin/typespec that referenced this pull request Aug 28, 2026
The C# `TypeExpression` threw a hard `Error` for anything it did not
recognise — tuples, string templates, enum members, template parameters
and most of the intrinsics. An emitter hitting one of those got a crash
with no source location instead of a diagnostic, so
`@typespec/http-server-csharp` had to wrap every call site in
`try`/`catch`.

Those kinds are now handled, and a genuinely unsupported type reports a
diagnostic against the offending type and falls back to `object`, so
compilation continues and the user gets a pointer to the spec that
caused it. The diagnostics name the type, so it is actionable without
bisecting the spec:

```
warning emitter-framework/csharp-unsupported-scalar: Scalar 'MyLib.ipAddress' has no
  C# equivalent, using 'object' instead. Extend a built-in scalar to control how it is emitted.

warning emitter-framework/csharp-unsupported-type: Type '@MyLib.flag' of kind 'Decorator'
  is not supported in C#, using 'object' instead.
```

The two are kept separate because they call for different actions: the
scalar one is fixable in the spec by extending a built-in scalar, while
the other reports a gap in the emitter.

Two smaller bugs fixed along the way:

- Unsupported scalars reported a **TypeScript** diagnostic
(`typescript-unsupported-scalar`) from the C# components. C# now has its
own `src/csharp/lib.ts`, matching the existing `typescript/lib.ts` and
`python/lib.ts`, which makes that class of mistake a type error.
- The `null` and `never` intrinsics emitted `null` and `never`, neither
of which is a C# type. They now emit `object` and `void`.

Also adds an `isCSharpValueType` util, since deciding whether a TypeSpec
type maps to a C# struct is something every C# emitter needs and every
C# emitter was reimplementing.

---

Independent — targets `main` and can merge on its own.

One of 7 PRs moving `@typespec/http-server-csharp` onto the emitter
framework instead of its private forks: microsoft#11596, microsoft#11597, microsoft#11598, microsoft#11599,
microsoft#11600, microsoft#11601, microsoft#11602.
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 stale Mark a PR that hasn't been recently updated and will be closed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants