resolveArmResources default legacy resource names can collide for nested resources
- Dominant language
- TypeScript
- Stars
- 27
- Forks
- 90
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 156
Description
## Summary
`resolveArmResources` can assign the same default `resourceName` to two distinct legacy ARM resources when their resource type paths share the same last two segments.
This preserves both resource identities, but downstream SDK emitters that use `resourceName` as a generated type name can collide and effectively drop one generated resource type.
## Observed case
Found while validating `@azure-tools/typespec-azure-resource-manager` `0.72.0-dev.1` in Azure/azure-sdk-for-net provisioning generation.
Compute has the same resource model, `VirtualMachineRunCommand`, reused under two different parent paths:
| ARM resource type | Expected distinct generated resource | Current default `resourceName` |
| --- | --- | --- |
| `Microsoft.Compute/virtualMachines/runCommands` | VM run command resource | `VirtualMachinesRunCommands` |
| `Microsoft.Compute/virtualMachineScaleSets/virtualMachines/runCommands` | VMSS VM run command resource | `VirtualMachinesRunCommands` |
Both resource projections are present in the provisioning emitter input (`tspCodeModel.json`), but both carry `resourceName = VirtualMachinesRunCommands`. The provisioning C# generator uses `resourceName` as the type/file name, so the two projections collide and only one `VirtualMachinesRunCommands.cs` remains.
## Root cause
The default legacy resource-name fallback uses only the final two resource type segments:
```ts
function getDefaultLegacyResourceName(operation: ArmResourceOperationData, httpOp: string): string {
const pathInfo = parseArmResourceInstancePath(httpOp);
if (pathInfo !== undefined) {
let types: string[] = pathInfo.resourceType.types;
if (types.length > 1) {
types = types.slice(types.length - 2);
}
return types.flatMap((t) => pascalCase(t)).join("");
} else {
return operation.resourceModelName;
}
}
```
For Compute:
- `virtualMachines/runCommands` -> `VirtualMachinesRunCommands`
- `virtualMachineScaleSets/virtualMachines/runCommands` -> last two segments are also `virtualMachines/runCommands` -> `VirtualMachinesRunCommands`
## Impact
Downstream emitters receive distinct resource identities but non-distinct names. Any emitter using `ResolvedResource.resourceName` as a type name or key can generate duplicate/colliding declarations.
## Expected behavior
Default resource names should be unique for distinct resource identities, or the API should expose enough disambiguation metadata for emitters to safely generate unique names.
Possible directions:
- Include more parent path context when the last-two-segment fallback collides.
- Preserve a collision-safe default name for legacy resources based on the full nested type path.
- Expose both the raw model/resource name and a collision-safe suggested name.
## Related validation
A focused resource identity test was added in Azure/typespec-azure#5247. That test verifies both resource paths are preserved; this issue is specifically about the duplicate `resourceName` assigned to those preserved identities.
Contributor guide
Assessment
This issue has not been assessed yet.