diff --git a/.chronus/changes/decorator-common-types-ref-2025-0-16-11-22-58.md b/.chronus/changes/decorator-common-types-ref-2025-0-16-11-22-58.md new file mode 100644 index 0000000000..bc843b7722 --- /dev/null +++ b/.chronus/changes/decorator-common-types-ref-2025-0-16-11-22-58.md @@ -0,0 +1,8 @@ +--- +changeKind: feature +packages: + - "@azure-tools/typespec-autorest" + - "@azure-tools/typespec-azure-resource-manager" +--- + +Add `@externalTypeRef` decorator, to been able to specify an external reference that should be used when emitting. diff --git a/packages/typespec-autorest/src/openapi.ts b/packages/typespec-autorest/src/openapi.ts index 3ef3f624bf..7be75d1a28 100644 --- a/packages/typespec-autorest/src/openapi.ts +++ b/packages/typespec-autorest/src/openapi.ts @@ -12,6 +12,7 @@ import { } from "@azure-tools/typespec-azure-core"; import { getArmCommonTypeOpenAPIRef, + getExternalTypeRef, isArmCommonType, isAzureResource, isConditionallyFlattened, @@ -936,6 +937,13 @@ export async function getOpenAPIForService( }; } + const externalTypeRefUrl = getExternalTypeRef(program, type); + if (externalTypeRefUrl) { + return { + $ref: expandRef(externalTypeRefUrl), + }; + } + if ( isArmCommonType(type) && (type.kind === "Model" || diff --git a/packages/typespec-azure-resource-manager/README.md b/packages/typespec-azure-resource-manager/README.md index 83f2165fc5..badb581b40 100644 --- a/packages/typespec-azure-resource-manager/README.md +++ b/packages/typespec-azure-resource-manager/README.md @@ -501,6 +501,7 @@ This allows sharing Azure Resource Manager resource types across specifications ### Azure.ResourceManager.Legacy - [`@customAzureResource`](#@customazureresource) +- [`@externalTypeRef`](#@externaltyperef) #### `@customAzureResource` @@ -518,3 +519,21 @@ but need to be identified as such. ##### Parameters None + +#### `@externalTypeRef` + +Specify an external reference that should be used when emitting this type. + +```typespec +@Azure.ResourceManager.Legacy.externalTypeRef(jsonRef: valueof string) +``` + +##### Target + +`Model | ModelProperty` + +##### Parameters + +| Name | Type | Description | +| ------- | ---------------- | ------------------------------------------------------------- | +| jsonRef | `valueof string` | External reference(e.g. "../../common.json#/definitions/Foo") | diff --git a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts index e956b75325..0955d90f24 100644 --- a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts +++ b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts @@ -4,6 +4,7 @@ import type { EnumValue, Interface, Model, + ModelProperty, Namespace, Operation, Type, @@ -266,6 +267,17 @@ export type ResourceBaseTypeDecorator = ( baseType: Type, ) => void; +/** + * * Specify an external reference that should be used when emitting this type. + * * @param jsonRef - External reference(e.g. "../../common.json#/definitions/Foo") + * + */ +export type ExternalTypeRefDecorator = ( + context: DecoratorContext, + entity: Model | ModelProperty, + jsonRef: string, +) => void; + export type AzureResourceManagerDecorators = { armResourceCollectionAction: ArmResourceCollectionActionDecorator; armProviderNameValue: ArmProviderNameValueDecorator; @@ -292,4 +304,5 @@ export type AzureResourceManagerDecorators = { export type AzureResourceManagerLegacyDecorators = { customAzureResource: CustomAzureResourceDecorator; + externalTypeRef: ExternalTypeRefDecorator; }; diff --git a/packages/typespec-azure-resource-manager/lib/Legacy/decorator.tsp b/packages/typespec-azure-resource-manager/lib/Legacy/decorator.tsp index d00ce1ed28..4f483d67ec 100644 --- a/packages/typespec-azure-resource-manager/lib/Legacy/decorator.tsp +++ b/packages/typespec-azure-resource-manager/lib/Legacy/decorator.tsp @@ -7,3 +7,9 @@ namespace Azure.ResourceManager.Legacy; * but need to be identified as such. */ extern dec customAzureResource(target: Model); + +/** + * Specify an external reference that should be used when emitting this type. + * @param jsonRef - External reference(e.g. "../../common.json#/definitions/Foo") + */ +extern dec externalTypeRef(entity: Model | ModelProperty, jsonRef: valueof string); diff --git a/packages/typespec-azure-resource-manager/src/common-types.ts b/packages/typespec-azure-resource-manager/src/common-types.ts index c91200dba9..13b5e2f984 100644 --- a/packages/typespec-azure-resource-manager/src/common-types.ts +++ b/packages/typespec-azure-resource-manager/src/common-types.ts @@ -14,7 +14,10 @@ import { isTypeSpecValueTypeOf, } from "@typespec/compiler"; import { $useDependency, getVersion } from "@typespec/versioning"; -import { ArmCommonTypesVersionDecorator } from "../generated-defs/Azure.ResourceManager.js"; +import { + ArmCommonTypesVersionDecorator, + ExternalTypeRefDecorator, +} from "../generated-defs/Azure.ResourceManager.js"; import { ArmCommonTypeRecord, ArmCommonTypesDefaultVersion, @@ -247,3 +250,15 @@ function resolveCommonTypesVersion( allVersions: allVersions ?? [], }; } + +export const $externalTypeRef: ExternalTypeRefDecorator = ( + context: DecoratorContext, + entity: Model | ModelProperty, + jsonRef: string, +) => { + context.program.stateMap(ArmStateKeys.externalTypeRef).set(entity, jsonRef); +}; + +export function getExternalTypeRef(program: Program, entity: Type): string | undefined { + return program.stateMap(ArmStateKeys.externalTypeRef).get(entity); +} diff --git a/packages/typespec-azure-resource-manager/src/index.ts b/packages/typespec-azure-resource-manager/src/index.ts index 7502dd992c..86865bc395 100644 --- a/packages/typespec-azure-resource-manager/src/index.ts +++ b/packages/typespec-azure-resource-manager/src/index.ts @@ -5,6 +5,7 @@ export { getArmCommonTypeOpenAPIRef, getArmCommonTypesVersion, getArmCommonTypesVersions, + getExternalTypeRef, isArmCommonType, type ArmCommonTypeVersions, type ArmCommonTypesResolutionOptions, diff --git a/packages/typespec-azure-resource-manager/src/state.ts b/packages/typespec-azure-resource-manager/src/state.ts index 7323a184d3..6ef6716671 100644 --- a/packages/typespec-azure-resource-manager/src/state.ts +++ b/packages/typespec-azure-resource-manager/src/state.ts @@ -14,6 +14,7 @@ export const ArmStateKeys = { armLibraryNamespaces: azureResourceManagerCreateStateSymbol("armLibraryNamespaces"), usesArmLibraryNamespaces: azureResourceManagerCreateStateSymbol("usesArmLibraryNamespaces"), armCommonTypesVersion: azureResourceManagerCreateStateSymbol("armCommonTypesVersion"), + externalTypeRef: azureResourceManagerCreateStateSymbol("externalTypeRef"), // resource.ts armResourcesCached: azureResourceManagerCreateStateSymbol("armResourcesCached"), diff --git a/packages/typespec-azure-resource-manager/src/tsp-index.ts b/packages/typespec-azure-resource-manager/src/tsp-index.ts index 2d0a27ea1b..ea04cf6ff9 100644 --- a/packages/typespec-azure-resource-manager/src/tsp-index.ts +++ b/packages/typespec-azure-resource-manager/src/tsp-index.ts @@ -3,7 +3,7 @@ import { AzureResourceManagerDecorators, AzureResourceManagerLegacyDecorators, } from "../generated-defs/Azure.ResourceManager.js"; -import { $armCommonTypesVersion } from "./common-types.js"; +import { $armCommonTypesVersion, $externalTypeRef } from "./common-types.js"; import { $armLibraryNamespace, $armProviderNamespace, $useLibraryNamespace } from "./namespace.js"; import { $armResourceAction, @@ -57,6 +57,7 @@ export const $decorators = { } satisfies AzureResourceManagerDecorators, "Azure.ResourceManager.Legacy": { customAzureResource: $customAzureResource, + externalTypeRef: $externalTypeRef, } satisfies AzureResourceManagerLegacyDecorators, }; diff --git a/packages/typespec-azure-resource-manager/test/arm-common-types-registration.test.ts b/packages/typespec-azure-resource-manager/test/arm-common-types-registration.test.ts index cd962b1c9c..1deb29bbac 100644 --- a/packages/typespec-azure-resource-manager/test/arm-common-types-registration.test.ts +++ b/packages/typespec-azure-resource-manager/test/arm-common-types-registration.test.ts @@ -1,8 +1,9 @@ import type { Diagnostic, Model, ModelProperty, Namespace } from "@typespec/compiler"; import { getService } from "@typespec/compiler"; import { expectDiagnosticEmpty, expectDiagnostics } from "@typespec/compiler/testing"; +import { strictEqual } from "assert"; import { describe, expect, it } from "vitest"; -import { findArmCommonTypeRecord } from "../src/common-types.js"; +import { findArmCommonTypeRecord, getExternalTypeRef } from "../src/common-types.js"; import type { ArmCommonTypeRecord } from "../src/commontypes.private.decorators.js"; import { createAzureResourceManagerTestRunner } from "./test-host.js"; @@ -205,3 +206,16 @@ describe("common parameters", () => { }); }); }); + +describe("common types ref", () => { + it("set external reference", async () => { + const runner = await createAzureResourceManagerTestRunner(); + const [{ Foo }, diagnostics] = await runner.compileAndDiagnose(` + @test @Azure.ResourceManager.Legacy.externalTypeRef("../common.json#/definitions/Foo") + model Foo {} + `); + + expectDiagnosticEmpty(diagnostics); + strictEqual(getExternalTypeRef(runner.program, Foo), "../common.json#/definitions/Foo"); + }); +}); diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/decorators.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/decorators.md index 9b2cc18146..b5b1520c55 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/decorators.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/decorators.md @@ -435,3 +435,21 @@ but need to be identified as such. #### Parameters None + +### `@externalTypeRef` {#@Azure.ResourceManager.Legacy.externalTypeRef} + +Specify an external reference that should be used when emitting this type. + +```typespec +@Azure.ResourceManager.Legacy.externalTypeRef(jsonRef: valueof string) +``` + +#### Target + +`Model | ModelProperty` + +#### Parameters + +| Name | Type | Description | +| ------- | ---------------- | ------------------------------------------------------------- | +| jsonRef | `valueof string` | External reference(e.g. "../../common.json#/definitions/Foo") | diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx index 88fbc6bd48..7c3821bb4d 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx @@ -269,6 +269,7 @@ npm install --save-peer @azure-tools/typespec-azure-resource-manager ### Decorators - [`@customAzureResource`](./decorators.md#@Azure.ResourceManager.Legacy.customAzureResource) +- [`@externalTypeRef`](./decorators.md#@Azure.ResourceManager.Legacy.externalTypeRef) ### Models