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,7 @@
---
changeKind: feature
packages:
- "@azure-tools/typespec-client-generator-core"
---

Add `isPreview` boolean to `SdkPackageType.metadata` to indicate whether the SDK targets any preview API versions.
7 changes: 7 additions & 0 deletions packages/typespec-client-generator-core/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,13 @@ export interface SdkPackage<TServiceOperation extends SdkServiceOperation> {
* If value is a string, the service is versioned with the specified version.
*/
apiVersions?: Map<string, string>;
/**
* Whether the package targets any preview API versions.
* `true` if any targeted API version has the `@previewVersion` decorator or matches the preview string regex.
* `false` if all versions are stable.
* `undefined` if no versioning is present.
*/
isPreview?: boolean;
};
}

Expand Down
25 changes: 25 additions & 0 deletions packages/typespec-client-generator-core/src/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getNamespaceFullName,
ignoreDiagnostics,
} from "@typespec/compiler";
import { isPreviewVersion } from "@azure-tools/typespec-azure-core";

import { prepareClientAndOperationCache } from "./cache.js";
import { createSdkClientType } from "./clients.js";
Expand Down Expand Up @@ -72,6 +73,7 @@ export async function createSdkPackage<TServiceOperation extends SdkServiceOpera
? [...versions.values()][0].at(-1)
: undefined,
apiVersions: apiVersionsMap,
isPreview: computeIsPreview(context, versions),
},
};
organizeNamespaces(context, sdkPackage);
Expand Down Expand Up @@ -202,3 +204,26 @@ async function computeCrossLanguageVersion(context: TCGCContext): Promise<string
const hex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
return hex.substring(0, 12);
}

function computeIsPreview(
context: TCGCContext,
versions: Map<unknown, string[]>,
): boolean | undefined {
const allVersions = [...versions.values()].flat();
if (allVersions.length === 0) {
return undefined;
}

// First check @previewVersion decorator on enum members
for (const versionEnum of context.getPackageVersionEnum().values()) {
if (!versionEnum) continue;
for (const member of versionEnum.members.values()) {
if (isPreviewVersion(context.program, member)) {
return true;
}
}
}

// Fall back to regex check for backward compatibility
return allVersions.some((v) => context.previewStringRegex.test(v));
}
Original file line number Diff line number Diff line change
Expand Up @@ -1525,3 +1525,87 @@ it("multi-service client has no versionsEnum", async () => {
ok(biClient.versionsEnum);
strictEqual(biClient.versionsEnum.name, "VersionsB");
});

it("isPreview is false for stable versions", async () => {
const { program } = await SimpleTester.compile(`
@service
@versioned(Versions)
namespace TestService;
enum Versions {
v1,
v2,
v3,
}
op test(): void;
`);

const context = await createSdkContextForTester(program);
const sdkPackage = context.sdkPackage;
strictEqual(sdkPackage.metadata.isPreview, false);
});

it("isPreview is undefined for unversioned service", async () => {
const { program } = await SimpleTester.compile(`
@service
namespace TestService;
op test(): void;
`);

const context = await createSdkContextForTester(program);
const sdkPackage = context.sdkPackage;
strictEqual(sdkPackage.metadata.apiVersion, undefined);
strictEqual(sdkPackage.metadata.isPreview, undefined);
});

it("isPreview is true for service with preview suffix version", async () => {
const { program } = await SimpleTester.compile(`
@service
@versioned(Versions)
namespace TestService;
enum Versions {
v2024_10_01_preview: "2024-10-01-preview",
}
op test(): void;
`);

const context = await createSdkContextForTester(program);
const sdkPackage = context.sdkPackage;
strictEqual(sdkPackage.metadata.isPreview, true);
});

it("isPreview is true for service with mixed stable and preview versions", async () => {
const { program } = await SimpleTester.compile(`
@service
@versioned(Versions)
namespace TestService;
enum Versions {
v2024_10_01: "2024-10-01",
v2024_11_01_preview: "2024-11-01-preview",
}
op test(): void;
`);

const context = await createSdkContextForTester(program);
const sdkPackage = context.sdkPackage;
strictEqual(sdkPackage.metadata.isPreview, true);
});

it("isPreview is true for service with @previewVersion decorator", async () => {
const { program } = await AzureCoreTester.compile(`
@service
@versioned(Versions)
namespace TestService;
enum Versions {
v2022_10_01: "2022-10-01",
#suppress "@azure-tools/typespec-azure-core/preview-version-last-member" "for test"
@previewVersion
v2022_11_01: "2022-11-01",
v2024_10_01: "2024-10-01",
}
op test(): void;
`);

const context = await createSdkContextForTester(program);
const sdkPackage = context.sdkPackage;
strictEqual(sdkPackage.metadata.isPreview, true);
});
Loading