Skip to content

fix(http-server-csharp): fix model file name when @friendlyName contains unresolved template placeholders - #11459

Open
abatishchev with Copilot wants to merge 4 commits into
mainfrom
copilot/http-server-csharp-bug-fix-name-tags-update
Open

fix(http-server-csharp): fix model file name when @friendlyName contains unresolved template placeholders#11459
abatishchev with Copilot wants to merge 4 commits into
mainfrom
copilot/http-server-csharp-bug-fix-name-tags-update

Conversation

Copilot AI commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

When @friendlyName stores a format string with {paramName} placeholders that weren't substituted (e.g. {name}TagsUpdate), the generated file was named {name}TagsUpdate.cs while the class inside was correctly named NameTagsUpdate — a discrepancy caused by the class name going through pascalCase() (which treats {/} as word separators) while the file path used the raw string.

Changes

  • src/components/models/model-helpers.ts — In getModelEmitName, sanitize the @friendlyName return value by replacing {paramName} placeholders with their PascalCase equivalents before using the name as a file path:

    return friendlyName.replace(/\{(\w+)\}/g, (_, n) => n.charAt(0).toUpperCase() + n.slice(1));

    {name}TagsUpdateNameTagsUpdate.cs, matching the emitted class name.

  • test/generation.test.ts — Regression test: verifies that a model decorated with @friendlyName("{name}TagsUpdate") produces NameTagsUpdate.cs with no literal {name} in the output path.

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

Copilot AI changed the title [WIP] Fix model file naming for NameTagsUpdate fix(http-server-csharp): fix model file name when @friendlyName contains unresolved template placeholders Jul 29, 2026
Copilot AI requested a review from abatishchev July 29, 2026 22:06
@abatishchev
abatishchev marked this pull request as ready for review July 29, 2026 22:12
@pkg-pr-new

pkg-pr-new Bot commented Jul 29, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/compiler@11459
npm i https://pkg.pr.new/@typespec/http-server-csharp@11459

commit: dfd71f3

@azure-sdk-automation

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

Comment thread packages/http-server-csharp/src/components/models/model-helpers.ts
Copilot AI and others added 2 commits July 29, 2026 16:57
… in model file names

Co-authored-by: abatishchev <351644+abatishchev@users.noreply.github.com>
… is a TemplateParameter

When `@friendlyName` is applied to a template model with a template parameter
as the sourceObject (e.g., `@friendlyName("{name}TagsUpdate", T)` on `Model<T>`),
the decorator is called on the template declaration with `sourceObject` being a
`TemplateParameter`. In that case, `replaceTemplatedStringFromProperties` leaves
the `{name}` placeholders unresolved in the stored friendly name.

Fix: in `$friendlyName`, return early when `sourceObject.kind === "TemplateParameter"`
rather than storing an unresolved format string. The decorator is re-applied when the
template is instantiated with a concrete type, which correctly resolves the placeholders.

Also:
- Revert the downstream workaround in `getModelEmitName` in http-server-csharp
- Update the http-server-csharp test to use the actual ARM-style template pattern
- Add a compiler test verifying template declarations don't get unresolved friendly names

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
@abatishchev
abatishchev force-pushed the copilot/http-server-csharp-bug-fix-name-tags-update branch from a7939a0 to dfd71f3 Compare July 29, 2026 23:57
@github-actions

Copy link
Copy Markdown
Contributor

❌ There is undocummented changes. Run chronus add to add a changeset or click here.

The following packages have changes but are not documented.

  • @typespec/compiler
Show changes

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

Fix generated model file name when @friendlyName contains unresolved template parameter placeholders such as {name} (e.g. {name}TagsUpdate). The file is now named using the PascalCase expansion of the placeholder (e.g. NameTagsUpdate.cs) instead of the literal {name}TagsUpdate.cs.

Comment thread packages/compiler/src/lib/decorators.ts Outdated
// Template parameters are not valid source objects - skip storing the friendly name
// for template declarations. The decorator will be re-applied when the template is
// instantiated with a concrete type, at which point the placeholders can be resolved.
if (sourceObject.kind === "TemplateParameter") {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@copilot we should never get to state where decorators are run with TemplateParameter passed to them , how did that happen? We should fix that even more upstream(in checker probably), and make sure to add a minimal regression test for that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. After investigating, the decorator is not actually called with TemplateParameter arguments in the first place — the checker already prevents it by setting skipDecorators: true when checking template declarations (checkModelStatement, checkInterface, etc.). The guard I had placed in decorators.ts was therefore at the wrong layer and solving a phantom problem.

Fixed in the latest commit:

  1. Removed the guard from decorators.ts — it was incorrect and misleading.

  2. Added an explicit guard in applyDecoratorToType (checker.ts) — this is the right place. The check skips the decorator if any argument is a TemplateParameter or TemplateParameterAccess. The checker's skipDecorators: true already prevents this path for normal template declarations, but this guard makes the protection explicit and future-proof.

  3. Updated the decorators.test.ts test — corrected the description to accurately explain the mechanism (skipDecorators: true in the checker, not a guard in the decorator), and retained the assertion that template declarations don't get unresolved friendly names while instantiations get correctly substituted names.

The existing tests in packages/compiler/test/checker/templates.test.ts (the "doesn't run decorators when checking template declarations" suite) already provide the minimal regression test for this behavior — they use @mark(T) with fail() to confirm the decorator is never invoked with an unresolved template parameter.

Copilot AI and others added 2 commits July 30, 2026 00:26
Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
Add a safety net in `applyDecoratorToType` (checker.ts) that skips running
a decorator when any of its arguments is an unresolved `TemplateParameter` or
`TemplateParameterAccess`. The checker already ensures decorators are not
applied to template declarations via `skipDecorators: true`, but this explicit
guard at the call site makes the protection robust and self-documenting.

Also:
- Revert the incorrect guard from `decorators.ts` (wrong layer)
- Revert the `getModelEmitName` sanitization workaround (not needed)
- Update test description in `decorators.test.ts` to accurately reflect
  the mechanism (skipDecorators, not a guard in the decorator itself)
- Update the `generation.test.ts` test to use the real ARM-style pattern

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: http-server-csharp: Generated model file for NameTagsUpdate is {name}TagsUpdate.cs

3 participants