Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9fb6730
Add the cloud setting option for ARM modular SDK
MaryGao Jun 3, 2025
7877136
Update the idea
MaryGao Jun 3, 2025
40c8971
Merge branch 'main' into support-multi-cloud-modular
MaryGao Jun 23, 2025
2b05dec
Build the cloud setting enum in model.ts
MaryGao Jun 23, 2025
ff301ca
Update the comments
MaryGao Jun 23, 2025
e98f8d8
Fix the generation issues
MaryGao Jun 23, 2025
a38ee5d
Refactor code a little to remove duplications
MaryGao Jun 23, 2025
5bfb860
Update the integration testings
MaryGao Jun 23, 2025
3705a0c
Fix the thrown exception messages
MaryGao Jun 23, 2025
7612429
Update the formats
MaryGao Jun 23, 2025
2711920
Directly use tcgc arm option
MaryGao Jun 23, 2025
4cb037a
Fix the UTs
MaryGao Jun 23, 2025
ed48054
Merge branch 'main' into support-multi-cloud-modular
MaryGao Jun 23, 2025
045ccbc
Update packages/typespec-ts/src/modular/buildClientContext.ts
MaryGao Jun 23, 2025
94d31cb
Regen the smoke with copilot comments
MaryGao Jun 23, 2025
5a63c55
Regen with smoke testing
MaryGao Jun 23, 2025
98680a0
Merge branch 'main' into support-multi-cloud-modular
MaryGao Jun 24, 2025
0f521eb
Merge branch 'main' into support-multi-cloud-modular
MaryGao Jun 24, 2025
a212372
Merge main into pr/MaryGao/3233 - resolved conflicts in cloud setting…
MaryGao Jul 15, 2025
abc02ad
Move the helper into our static helper folder
MaryGao Jul 15, 2025
b8a37b7
Remove the baseurl
MaryGao Jul 15, 2025
21cbaee
Update the un-necessary codes
MaryGao Jul 15, 2025
ca885b7
Update the un-necessary codes
MaryGao Jul 15, 2025
4183b3a
Fix the UTs
MaryGao Jul 15, 2025
c66ce82
Fix the UTs
MaryGao Jul 15, 2025
d8258cc
Update packages/typespec-ts/src/modular/buildRootIndex.ts
MaryGao Jul 15, 2025
8df5e7d
Update the comments
MaryGao Jul 15, 2025
2824202
Merge branch 'support-multi-cloud-modular' of https://github.com/mary…
MaryGao Jul 15, 2025
d2ba539
Update the copilot suggestion
MaryGao Jul 15, 2025
5ce951b
Update the git diff
MaryGao Jul 15, 2025
99a0b4f
Regen modular integration test
MaryGao Jul 15, 2025
03ebf2c
Update packages/typespec-test/test/NetworkAnalytics.Management/genera…
MaryGao Jul 16, 2025
e24c68d
Update packages/typespec-test/test/NetworkAnalytics.Management/genera…
MaryGao Jul 16, 2025
c213829
Refresh the smoke test and integration test
MaryGao Jul 16, 2025
5d5610d
Update the index file
MaryGao Jul 16, 2025
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
Expand Up @@ -28,6 +28,16 @@ export interface AccountSasToken {
// @public
export type ActionType = string;

// @public
export enum AzureClouds {
AZURE_CHINA_CLOUD = "AZURE_CHINA_CLOUD",
AZURE_PUBLIC_CLOUD = "AZURE_PUBLIC_CLOUD",
AZURE_US_GOVERNMENT = "AZURE_US_GOVERNMENT"
}

// @public
export type AzureSupportedClouds = `${AzureClouds}`;

// @public
export interface ConsumptionEndpointsProperties {
readonly fileAccessResourceId?: string;
Expand Down Expand Up @@ -442,6 +452,7 @@ export class NetworkAnalyticsApi {
// @public
export interface NetworkAnalyticsApiOptionalParams extends ClientOptions {
apiVersion?: string;
cloudSetting?: AzureSupportedClouds;
}

// @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

import { logger } from "../logger.js";
import { KnownVersions } from "../models/models.js";
import {
AzureSupportedClouds,
getArmEndpoint,
} from "../static-helpers/cloudSettingHelpers.js";
import { Client, ClientOptions, getClient } from "@azure-rest/core-client";
import { TokenCredential } from "@azure/core-auth";

Expand All @@ -19,14 +23,19 @@ export interface NetworkAnalyticsApiOptionalParams extends ClientOptions {
/** The API version to use for this operation. */
/** Known values of {@link KnownVersions} that the service accepts. */
apiVersion?: string;
/** Specifies the Azure cloud environment for the client. */
cloudSetting?: AzureSupportedClouds;
}

export function createNetworkAnalyticsApi(
credential: TokenCredential,
subscriptionId: string,
options: NetworkAnalyticsApiOptionalParams = {},
): NetworkAnalyticsApiContext {
const endpointUrl = options.endpoint ?? "https://management.azure.com";
const endpointUrl =
options.endpoint ??
getArmEndpoint(options.cloudSetting) ??
"https://management.azure.com";
const prefixFromOptions = options?.userAgentOptions?.userAgentPrefix;
const userAgentInfo = `azsdk-js-arm-networkanalytics/1.0.0-beta.1`;
const userAgentPrefix = prefixFromOptions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import {
AzureClouds,
AzureSupportedClouds,
} from "./static-helpers/cloudSettingHelpers.js";
import {
PageSettings,
ContinuablePage,
Expand Down Expand Up @@ -104,3 +108,4 @@ export {
OperationsOperations,
} from "./classic/index.js";
export { PageSettings, ContinuablePage, PagedAsyncIterableIterator };
export { AzureClouds, AzureSupportedClouds };
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/** An enum to describe Azure Cloud. */
export enum AzureClouds {
/** Azure public cloud, which is the default cloud for Azure SDKs. */
AZURE_PUBLIC_CLOUD = "AZURE_PUBLIC_CLOUD",
/** Azure China cloud */
AZURE_CHINA_CLOUD = "AZURE_CHINA_CLOUD",
/** Azure US government cloud */
AZURE_US_GOVERNMENT = "AZURE_US_GOVERNMENT",
}

/** The supported values for cloud setting as a string literal type */
export type AzureSupportedClouds = `${AzureClouds}`;

export function getArmEndpoint(
cloudSetting?: AzureSupportedClouds,
): string | undefined {
if (cloudSetting === undefined) {
return undefined;
}
const cloudEndpoints: Record<keyof typeof AzureClouds, string> = {
AZURE_CHINA_CLOUD: "https://management.chinacloudapi.cn/",
AZURE_US_GOVERNMENT: "https://management.usgovcloudapi.net/",
AZURE_PUBLIC_CLOUD: "https://management.azure.com/",
};
if (cloudSetting in cloudEndpoints) {
return cloudEndpoints[cloudSetting];
} else {
throw new Error(
`Unknown cloud setting: ${cloudSetting}. Please refer to the enum AzureClouds for possible values.`,
);
}
}
6 changes: 5 additions & 1 deletion packages/typespec-ts/src/framework/load-static-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { readdir, stat, readFile } from "fs/promises";
import * as path from "path";
import {
ClassDeclaration,
EnumDeclaration,
FunctionDeclaration,
InterfaceDeclaration,
Project,
Expand All @@ -15,7 +16,7 @@ import { ModularEmitterOptions } from "../modular/interfaces.js";
export const SourceFileSymbol = Symbol("SourceFile");
export interface StaticHelperMetadata {
name: string;
kind: "function" | "interface" | "typeAlias" | "class";
kind: "function" | "interface" | "typeAlias" | "class" | "enum";
location: string;
[SourceFileSymbol]?: SourceFile;
}
Expand Down Expand Up @@ -137,6 +138,7 @@ function getDeclarationByMetadata(
| FunctionDeclaration
| TypeAliasDeclaration
| InterfaceDeclaration
| EnumDeclaration
| undefined {
switch (declaration.kind) {
case "class":
Expand All @@ -147,6 +149,8 @@ function getDeclarationByMetadata(
return file.getInterface(declaration.name);
case "typeAlias":
return file.getTypeAlias(declaration.name);
case "enum":
return file.getEnum(declaration.name);
default:
throw new Error(
`invalid helper kind ${declaration.kind}\nAll helpers provided to loadStaticHelpers are of kind: function, interface, typeAlias, class`
Expand Down
4 changes: 3 additions & 1 deletion packages/typespec-ts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { EmitContext, Program } from "@typespec/compiler";
import { GenerationDirDetail, SdkContext } from "./utils/interfaces.js";
import {
CloudSettingHelpers,
MultipartHelpers,
PagingHelpers,
PollingHelpers,
Expand Down Expand Up @@ -130,7 +131,8 @@ export async function $onEmit(context: EmitContext) {
...PagingHelpers,
...PollingHelpers,
...UrlTemplateHelpers,
...MultipartHelpers
...MultipartHelpers,
...CloudSettingHelpers
},
{
sourcesDir: dpgContext.generationPathDetail?.modularSourcesDir,
Expand Down
6 changes: 6 additions & 0 deletions packages/typespec-ts/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,12 @@ const libDef = {
messages: {
default: paramMessage`The property name ${"propertyName"} has conflicts with others and please use @clientName to rename it.`
}
},
"parameter-name-conflict": {
severity: "warning",
messages: {
default: paramMessage`The parameter name ${"parameterName"} has conflicts with others and please use @clientName to rename it.`
}
}
},
emitter: {
Expand Down
54 changes: 39 additions & 15 deletions packages/typespec-ts/src/modular/buildClientContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import {
import { getModularClientOptions } from "../utils/clientUtils.js";
import { useContext } from "../contextManager.js";
import { refkey } from "../framework/refkey.js";
import { reportDiagnostic } from "../lib.js";
import { NoTarget } from "@typespec/compiler";
import { CloudSettingHelpers } from "./static-helpers-metadata.js";

/**
* This function gets the path of the file containing the modular client context
Expand Down Expand Up @@ -100,25 +103,46 @@ export function buildClientContext(
})
});

const propertiesInOptions = getClientParameters(client, dpgContext, {
optionalOnly: true
})
.filter((p) => p.name !== "endpoint")
.map((p) => {
return {
name: getClientParameterName(p),
type:
p.name.toLowerCase() === "apiversion"
? "string"
: getTypeExpression(dpgContext, p.type),
hasQuestionToken: true,
docs: getDocsWithKnownVersion(dpgContext, p)
};
});
if (dpgContext.arm) {
propertiesInOptions.push({
name: "cloudSetting",
type: `${resolveReference(CloudSettingHelpers.AzureSupportedClouds)}`,
hasQuestionToken: true,
docs: [`Specifies the Azure cloud environment for the client.`]
});
}
// check if we have duplication options
const existingOptionNames = new Set<string>();
for (const property of propertiesInOptions) {
if (existingOptionNames.has(property.name)) {
reportDiagnostic(dpgContext.program, {
code: "parameter-name-conflict",
format: { parameterName: property.name },
target: NoTarget
});
}
existingOptionNames.add(property.name);
}
clientContextFile.addInterface({
name: `${getClassicalClientName(client)}OptionalParams`,
isExported: true,
extends: [resolveReference(dependencies.ClientOptions)],
properties: getClientParameters(client, dpgContext, {
optionalOnly: true
})
.filter((p) => p.name !== "endpoint")
.map((p) => {
return {
name: getClientParameterName(p),
type:
p.name.toLowerCase() === "apiversion"
? "string"
: getTypeExpression(dpgContext, p.type),
hasQuestionToken: true,
docs: getDocsWithKnownVersion(dpgContext, p)
};
}),
properties: propertiesInOptions,
docs: ["Optional parameters for the client."]
});

Expand Down
50 changes: 28 additions & 22 deletions packages/typespec-ts/src/modular/buildRootIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { Project, SourceFile } from "ts-morph";
import { getClassicalClientName } from "./helpers/namingHelpers.js";
import { ModularEmitterOptions } from "./interfaces.js";
import { resolveReference } from "../framework/reference.js";
import { MultipartHelpers, PagingHelpers } from "./static-helpers-metadata.js";
import {
CloudSettingHelpers,
MultipartHelpers,
PagingHelpers
} from "./static-helpers-metadata.js";
import {
SdkClientType,
SdkContext,
Expand Down Expand Up @@ -68,6 +72,7 @@ export function buildRootIndex(

exportPagingTypes(context, rootIndexFile);
exportFileContentsType(context, rootIndexFile);
exportAzureCloudTypes(context, rootIndexFile);
}

function exportModels(
Expand All @@ -91,6 +96,15 @@ function exportModels(
}
}

function exportAzureCloudTypes(context: SdkContext, rootIndexFile: SourceFile) {
if (context.arm) {
addExportsToRootIndexFile(rootIndexFile, [
resolveReference(CloudSettingHelpers.AzureClouds),
resolveReference(CloudSettingHelpers.AzureSupportedClouds)
]);
}
}

/**
* This is a temporary solution for adding paging exports. Eventually we will have the binder generate the exports automatically.
*/
Expand All @@ -99,18 +113,11 @@ function exportPagingTypes(context: SdkContext, rootIndexFile: SourceFile) {
return;
}

const existingExports = getExistingExports(rootIndexFile);
const namedExports = [
addExportsToRootIndexFile(rootIndexFile, [
resolveReference(PagingHelpers.PageSettings),
resolveReference(PagingHelpers.ContinuablePage),
resolveReference(PagingHelpers.PagedAsyncIterableIterator)
];

const newNamedExports = getNewNamedExports(namedExports, existingExports);

if (newNamedExports.length > 0) {
addExportsToRootIndexFile(rootIndexFile, newNamedExports);
}
]);
}

function hasPaging(context: SdkContext): boolean {
Expand Down Expand Up @@ -139,14 +146,9 @@ function exportFileContentsType(
)
)
) {
const existingExports = getExistingExports(rootIndexFile);
const namedExports = [resolveReference(MultipartHelpers.FileContents)];

const newNamedExports = getNewNamedExports(namedExports, existingExports);

if (newNamedExports.length > 0) {
addExportsToRootIndexFile(rootIndexFile, newNamedExports);
}
addExportsToRootIndexFile(rootIndexFile, [
resolveReference(MultipartHelpers.FileContents)
]);
}
}

Expand All @@ -171,11 +173,15 @@ function getNewNamedExports(

function addExportsToRootIndexFile(
rootIndexFile: SourceFile,
newNamedExports: string[]
namedExports: string[]
) {
rootIndexFile.addExportDeclaration({
namedExports: newNamedExports
});
const existingExports = getExistingExports(rootIndexFile);
const newNamedExports = getNewNamedExports(namedExports, existingExports);
if (newNamedExports.length > 0) {
rootIndexFile.addExportDeclaration({
namedExports: newNamedExports
});
}
}

function exportRestoreHelpers(
Expand Down
14 changes: 12 additions & 2 deletions packages/typespec-ts/src/modular/helpers/clientHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { SdkContext } from "../../utils/interfaces.js";
import { getClassicalClientName } from "./namingHelpers.js";
import { getTypeExpression } from "../type-expressions/get-type-expression.js";
import { isCredentialType } from "./typeHelpers.js";
import { CloudSettingHelpers } from "../static-helpers-metadata.js";
import { resolveReference } from "../../framework/reference.js";

interface ClientParameterOptions {
onClientOnly?: boolean;
Expand Down Expand Up @@ -170,8 +172,16 @@ export function buildGetClientEndpointParam(
dpgContext: SdkContext,
client: SdkClientType<SdkServiceOperation>
): string {
const coreEndpointParam = `options.endpoint`;

let coreEndpointParam = "";
if (dpgContext.rlcOptions?.flavor === "azure") {
const cloudSettingSuffix = dpgContext.arm
? ` ?? ${resolveReference(CloudSettingHelpers.getArmEndpoint)}(options.cloudSetting)`
: "";
coreEndpointParam = `options.endpoint${cloudSettingSuffix}`;
} else {
// unbranded does not have the deprecated baseUrl parameter
coreEndpointParam = `options.endpoint`;
}
// Special case: endpoint URL not defined
const endpointParam = getClientParameters(client, dpgContext, {
onClientOnly: true,
Expand Down
18 changes: 18 additions & 0 deletions packages/typespec-ts/src/modular/static-helpers-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,21 @@ export const MultipartHelpers = {
location: "multipartHelpers.ts"
}
} as const;

export const CloudSettingHelpers = {
AzureClouds: {
kind: "enum",
name: "AzureClouds",
location: "cloudSettingHelpers.ts"
},
AzureSupportedClouds: {
kind: "typeAlias",
name: "AzureSupportedClouds",
location: "cloudSettingHelpers.ts"
},
getArmEndpoint: {
kind: "function",
name: "getArmEndpoint",
location: "cloudSettingHelpers.ts"
}
} as const;
Loading
Loading