Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@azure-tools/typespec-azure-resource-manager"
---

Remove single service restriction for ARM specs
6 changes: 0 additions & 6 deletions packages/typespec-azure-resource-manager/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ import { createTypeSpecLibrary, paramMessage } from "@typespec/compiler";
export const $lib = createTypeSpecLibrary({
name: "@azure-tools/typespec-azure-resource-manager",
diagnostics: {
"single-arm-provider": {
severity: "error",
messages: {
default: "Only one @armProviderNamespace can be declared in a typespec spec at once.",
},
},
"decorator-param-wrong-type": {
severity: "error",
messages: {
Expand Down
10 changes: 0 additions & 10 deletions packages/typespec-azure-resource-manager/src/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
UseLibraryNamespaceDecorator,
} from "../generated-defs/Azure.ResourceManager.js";
import { $armCommonTypesVersion } from "./common-types.js";
import { reportDiagnostic } from "./lib.js";
import { getArmVirtualResourceDetails, getSingletonResourceKey } from "./resource.js";
import { ArmStateKeys } from "./state.js";

Expand Down Expand Up @@ -143,15 +142,6 @@ export const $armProviderNamespace: ArmProviderNamespaceDecorator = (

const inRealm = unsafe_Realm.realmForType.has(entity);
const override = isArmNamespaceOverride(program, entity);
const namespaceCount = program.stateMap(ArmStateKeys.armProviderNamespaces).size;
if (namespaceCount > 0 && !override && !inRealm) {
reportDiagnostic(program, {
code: "single-arm-provider",
target: context.decoratorTarget,
});
return;
}

// armProviderNamespace will set the service namespace if it's not done already
if (!override || inRealm) {
addService(program, entity);
Expand Down
29 changes: 29 additions & 0 deletions packages/typespec-azure-resource-manager/test/resource.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1204,3 +1204,32 @@ it("recognizes resource with customResource identifier", async () => {
`);
expectDiagnosticEmpty(diagnostics);
});

describe("multiple services", () => {
it("assign resources to the correct service", async () => {
const { program } = await Tester.compile(`
@armProviderNamespace
namespace Microsoft.ServiceA {
model ResA is TrackedResource<{}> {
@key @segment("foos") @path name: string;
}
}

@armProviderNamespace
namespace Microsoft.ServiceB {
model ResB is TrackedResource<{}> {
@key @segment("foos") @path name: string;
}
}
`);
Comment on lines +1211 to +1224
Copy link
Member

@ArcturusZhang ArcturusZhang Nov 26, 2025

Choose a reason for hiding this comment

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

so how would it behave if we have two parts with the same provider namespace but with different api version enum? this case happen in compute.
Do we have to do something like this?

@providerNamespace("Microsoft.Compute")
@versioned(VMVersions)
namespace Microsoft.Compute.Vms {}

@providerNamespace("Microsoft.Compute")
@versioned(DiskVersions)
namespace Microsoft.Compute.Disks {}

and if we have to do it in the above way, we might not be able to just put them into the one client.tsp without changing their specs.

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah that would be how to do it I asssume playground


const resources = getArmResources(program);
Copy link
Member

Choose a reason for hiding this comment

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

I think there is a plan that we deprecate this API.
Should we use resolveArmResources instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

hhm maybe but this is what all the tests in this file are using and I don't think it will fully go away(at least internally) as this is just the low level accessor

expect(resources).toHaveLength(2);

const [ResA, ResB] = resources;
expect(ResA.name).toEqual("ResA");
expect(ResA.armProviderNamespace).toEqual("Microsoft.ServiceA");
expect(ResB.name).toEqual("ResB");
expect(ResB.armProviderNamespace).toEqual("Microsoft.ServiceB");
});
});
Loading