fix(http-server-csharp): prevent _2 suffix on generated class/interface names from library namespace collisions - #11496
fix(http-server-csharp): prevent _2 suffix on generated class/interface names from library namespace collisions#11496abatishchev with Copilot wants to merge 1 commit into
_2 suffix on generated class/interface names from library namespace collisions#11496Conversation
|
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. |
_2 suffix on generated class/interface names from library namespace collisions
commit: |
…cting collection to @service namespaces When a library namespace (e.g. Azure.ResourceManager) defines interfaces or models with the same name as those in the user's @service namespace, the emitter previously collected both, causing alloy-js to rename the second occurrence with a _2 suffix (e.g. OperationsController_2, IOperations_2, ErrorResponse_2). Fix getServiceInterfaces (service-discovery.ts) and getServiceModels (service-resolution.ts) to restrict their initial collection to @service-decorated namespaces via listServices(program). A fallback to the old all-namespace behaviour is kept for TypeSpec programs without @service. Models transitively referenced by service operations (in any namespace) are still discovered and emitted through discoverReferencedModels/discoverModelsInType. Closes #11493 Co-authored-by: abatishchev <351644+abatishchev@users.noreply.github.com>
dfa6c41 to
29baac6
Compare
|
All changed packages have been documented.
Show changes
|
timotheeguerin
left a comment
There was a problem hiding this comment.
Need to tweak a little the test and actual goal of the PR(comments are targetted for copilot to apply if they sound a little harsh)
| // got a `_2` suffix, causing a class/constructor name mismatch in the generated C#. | ||
| it("does not emit _2 suffix when a non-service namespace has an interface with the same name", async () => { | ||
| const spec = ` | ||
| // Simulate a library namespace (e.g. Azure.ResourceManager) that has its own |
There was a problem hiding this comment.
Simplify this test, the azure mention are irrelevant, here we just want to test that we don't include unreachable types that are not in the service namespace
Do not include extra info keep the bare minimum needed in this test
| const [, controllerContents] = controllerFile!; | ||
| const [, interfaceContents] = interfaceFile!; | ||
|
|
||
| assert.ok( |
There was a problem hiding this comment.
those expect feel very speciifc to this instance and could easily not be testing the actual problem if the dedup logic change.
We should maybe simplify that to just check the whole set of generated models and make sure there is no unexpected one
| collectModelsFromNamespace($, ns, models, seen, authModels); | ||
| } | ||
| const services = listServices(program); | ||
| if (services.length > 0) { |
There was a problem hiding this comment.
lets reformulate this as we do not want to include type that are not defined in the service namespace unless they are referenced.
When a library namespace (e.g.
Azure.ResourceManager) defines interfaces or models with the same name as those in the user's@servicenamespace, the emitter was collecting both, causing alloy-js to rename the second occurrence with a_2suffix — producing invalid C# where the class name and constructor name no longer match:Root cause
getServiceInterfacesandgetServiceModelstraversed all non-standard namespaces in the global namespace tree, including library namespaces likeAzure.ResourceManager. ARM RP specs define concreteOperationsinterfaces and common types (e.g.ErrorResponse) in those namespaces; when the same name appeared in the user's service namespace, both were emitted and the second got_2appended to its class declaration.Changes
service-discovery.ts—getServiceInterfaces: Now callslistServices(program)and only collects interfaces from@service-decorated namespaces. Falls back to the previous all-namespace scan when no@servicedecorator is present (e.g. unit tests).service-resolution.ts—getServiceModels: Same scoping applied to the initial namespace model collection and thediscoverReferencedModelsstarting points. Models transitively referenced by service operations (regardless of which namespace they live in) continue to be discovered and emitted viadiscoverModelsInType.test/service-discovery.test.ts: New regression tests covering both the interface/controller case and the model case.