@azure-tools/typespec-ts 0.46.1 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +15 -3
  2. package/LICENSE +21 -0
  3. package/dist/src/framework/hooks/sdkTypes.d.ts +7 -1
  4. package/dist/src/framework/hooks/sdkTypes.d.ts.map +1 -1
  5. package/dist/src/framework/hooks/sdkTypes.js +59 -1
  6. package/dist/src/framework/hooks/sdkTypes.js.map +1 -1
  7. package/dist/src/index.d.ts.map +1 -1
  8. package/dist/src/index.js +2 -1
  9. package/dist/src/index.js.map +1 -1
  10. package/dist/src/lib.d.ts +20 -1
  11. package/dist/src/lib.d.ts.map +1 -1
  12. package/dist/src/lib.js +18 -1
  13. package/dist/src/lib.js.map +1 -1
  14. package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
  15. package/dist/src/modular/buildClassicalClient.js +137 -23
  16. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  17. package/dist/src/modular/buildRootIndex.d.ts +2 -1
  18. package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
  19. package/dist/src/modular/buildRootIndex.js +23 -0
  20. package/dist/src/modular/buildRootIndex.js.map +1 -1
  21. package/dist/src/modular/emitModels.d.ts.map +1 -1
  22. package/dist/src/modular/emitModels.js +57 -14
  23. package/dist/src/modular/emitModels.js.map +1 -1
  24. package/dist/src/modular/emitSamples.d.ts.map +1 -1
  25. package/dist/src/modular/emitSamples.js +53 -26
  26. package/dist/src/modular/emitSamples.js.map +1 -1
  27. package/dist/src/modular/helpers/classicalOperationHelpers.d.ts.map +1 -1
  28. package/dist/src/modular/helpers/classicalOperationHelpers.js +73 -23
  29. package/dist/src/modular/helpers/classicalOperationHelpers.js.map +1 -1
  30. package/dist/src/modular/helpers/operationHelpers.d.ts +7 -4
  31. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  32. package/dist/src/modular/helpers/operationHelpers.js +115 -23
  33. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  34. package/dist/src/modular/helpers/typeHelpers.d.ts +3 -1
  35. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  36. package/dist/src/modular/helpers/typeHelpers.js +7 -3
  37. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  38. package/dist/src/modular/serialization/buildDeserializerFunction.d.ts +4 -2
  39. package/dist/src/modular/serialization/buildDeserializerFunction.d.ts.map +1 -1
  40. package/dist/src/modular/serialization/buildDeserializerFunction.js +60 -17
  41. package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
  42. package/dist/src/modular/serialization/buildSerializerFunction.d.ts +4 -2
  43. package/dist/src/modular/serialization/buildSerializerFunction.d.ts.map +1 -1
  44. package/dist/src/modular/serialization/buildSerializerFunction.js +61 -19
  45. package/dist/src/modular/serialization/buildSerializerFunction.js.map +1 -1
  46. package/dist/src/modular/serialization/serializeUtils.d.ts +11 -0
  47. package/dist/src/modular/serialization/serializeUtils.d.ts.map +1 -1
  48. package/dist/src/modular/serialization/serializeUtils.js +15 -0
  49. package/dist/src/modular/serialization/serializeUtils.js.map +1 -1
  50. package/dist/src/modular/static-helpers-metadata.d.ts +17 -0
  51. package/dist/src/modular/static-helpers-metadata.d.ts.map +1 -1
  52. package/dist/src/modular/static-helpers-metadata.js +17 -0
  53. package/dist/src/modular/static-helpers-metadata.js.map +1 -1
  54. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  55. package/dist/src/transform/transfromRLCOptions.js +2 -0
  56. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  57. package/dist/src/utils/namespaceUtils.d.ts.map +1 -1
  58. package/dist/src/utils/namespaceUtils.js +19 -4
  59. package/dist/src/utils/namespaceUtils.js.map +1 -1
  60. package/dist/src/utils/operationUtil.d.ts +1 -0
  61. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  62. package/dist/src/utils/operationUtil.js +26 -0
  63. package/dist/src/utils/operationUtil.js.map +1 -1
  64. package/dist/tsconfig.tsbuildinfo +1 -1
  65. package/package.json +7 -11
  66. package/src/framework/hooks/sdkTypes.ts +102 -2
  67. package/src/index.ts +2 -0
  68. package/src/lib.ts +20 -1
  69. package/src/modular/buildClassicalClient.ts +182 -25
  70. package/src/modular/buildRootIndex.ts +53 -1
  71. package/src/modular/emitModels.ts +72 -19
  72. package/src/modular/emitSamples.ts +86 -21
  73. package/src/modular/helpers/classicalOperationHelpers.ts +112 -30
  74. package/src/modular/helpers/operationHelpers.ts +163 -43
  75. package/src/modular/helpers/typeHelpers.ts +19 -3
  76. package/src/modular/serialization/buildDeserializerFunction.ts +87 -35
  77. package/src/modular/serialization/buildSerializerFunction.ts +86 -36
  78. package/src/modular/serialization/serializeUtils.ts +37 -0
  79. package/src/modular/static-helpers-metadata.ts +18 -0
  80. package/src/transform/transfromRLCOptions.ts +2 -0
  81. package/src/utils/namespaceUtils.ts +19 -3
  82. package/src/utils/operationUtil.ts +35 -0
  83. package/static/static-helpers/serialization/check-prop-undefined.ts +17 -0
  84. package/static/static-helpers/simplePollerHelpers.ts +125 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.46.1",
3
+ "version": "0.47.0",
4
4
  "description": "An experimental TypeSpec emitter for TypeScript RLC",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -18,14 +18,14 @@
18
18
  "license": "MIT",
19
19
  "devDependencies": {
20
20
  "@azure-rest/core-client": "^2.3.1",
21
- "@typespec/http-specs": "0.1.0-alpha.29-dev.2",
22
- "@typespec/spector": "0.1.0-alpha.21-dev.1",
23
- "@typespec/spec-api": "0.1.0-alpha.11-dev.0",
21
+ "@typespec/http-specs": "0.1.0-alpha.29-dev.5",
22
+ "@typespec/spector": "0.1.0-alpha.21-dev.3",
23
+ "@typespec/spec-api": "0.1.0-alpha.11-dev.1",
24
24
  "@typespec/tspd": "0.73.1",
25
- "@azure-tools/azure-http-specs": "0.1.0-alpha.33-dev.0",
25
+ "@azure-tools/azure-http-specs": "0.1.0-alpha.33-dev.4",
26
26
  "@azure-tools/typespec-autorest": "^0.62.0",
27
27
  "@azure-tools/typespec-azure-core": "^0.62.0",
28
- "@azure-tools/typespec-azure-resource-manager": "^0.62.0",
28
+ "@azure-tools/typespec-azure-resource-manager": "^0.62.1",
29
29
  "@azure-tools/typespec-client-generator-core": "^0.62.0",
30
30
  "@azure/abort-controller": "^2.1.2",
31
31
  "@azure/core-auth": "^1.6.0",
@@ -38,7 +38,6 @@
38
38
  "@types/fs-extra": "^9.0.13",
39
39
  "@types/lodash": "^4.17.4",
40
40
  "@types/mocha": "^10.0.6",
41
- "@types/node": "^18.0.0",
42
41
  "@typescript-eslint/eslint-plugin": "^8.28.0",
43
42
  "@typescript-eslint/parser": "^8.28.0",
44
43
  "@typespec/compiler": "^1.6.0",
@@ -51,14 +50,11 @@
51
50
  "chalk": "^4.0.0",
52
51
  "cross-env": "^7.0.3",
53
52
  "eslint-plugin-require-extensions": "0.1.3",
54
- "eslint": "^8.9.0",
55
53
  "mkdirp": "^3.0.1",
56
54
  "mocha": "^10.4.0",
57
55
  "npm-run-all": "~4.1.5",
58
56
  "prettier": "^3.3.3",
59
- "rimraf": "^5.0.0",
60
57
  "ts-node": "~10.9.1",
61
- "typescript": "~5.8.2",
62
58
  "vitest": "~1.6.0",
63
59
  "@vitest/coverage-v8": "~1.6.0",
64
60
  "@vitest/coverage-istanbul": "~1.6.0",
@@ -77,7 +73,7 @@
77
73
  "@typespec/xml": "^0.76.0"
78
74
  },
79
75
  "dependencies": {
80
- "@azure-tools/rlc-common": "^0.46.1",
76
+ "@azure-tools/rlc-common": "^0.47.0",
81
77
  "fs-extra": "^11.1.0",
82
78
  "lodash": "^4.17.21",
83
79
  "prettier": "^3.3.3",
@@ -2,6 +2,8 @@ import { Operation, Type, getNamespaceFullName } from "@typespec/compiler";
2
2
  import {
3
3
  SdkClientType,
4
4
  SdkHttpOperation,
5
+ SdkModelPropertyType,
6
+ SdkModelType,
5
7
  SdkServiceMethod,
6
8
  SdkType,
7
9
  getClientType
@@ -10,12 +12,27 @@ import { provideContext, useContext } from "../../contextManager.js";
10
12
 
11
13
  import { visitPackageTypes } from "../../modular/emitModels.js";
12
14
  import { SdkContext } from "../../utils/interfaces.js";
15
+ import {
16
+ getAllAncestors,
17
+ getAllProperties
18
+ } from "../../modular/helpers/operationHelpers.js";
19
+ import { normalizeModelPropertyName } from "../../modular/type-expressions/get-type-expression.js";
20
+ import { reportDiagnostic } from "../../lib.js";
21
+ import { NameType, normalizeName } from "@azure-tools/rlc-common";
13
22
 
14
23
  export const emitQueue: Set<SdkType> = new Set<SdkType>();
24
+ export const flattenPropertyModelMap: Map<SdkModelPropertyType, SdkModelType> =
25
+ new Map<SdkModelPropertyType, SdkModelType>();
15
26
 
16
27
  export interface SdkTypeContext {
17
28
  operations: Map<Type, SdkServiceMethod<SdkHttpOperation>>;
18
29
  types: Map<Type, SdkType>;
30
+ flattenProperties: Map<SdkModelPropertyType, SdkFlattenPropertyContext>;
31
+ }
32
+
33
+ export interface SdkFlattenPropertyContext {
34
+ baseModel: SdkModelType;
35
+ conflictMap?: Map<SdkModelPropertyType, string>;
19
36
  }
20
37
 
21
38
  export function useSdkTypes() {
@@ -56,11 +73,20 @@ export function useSdkTypes() {
56
73
 
57
74
  export function provideSdkTypes(context: SdkContext) {
58
75
  const { sdkPackage } = context;
59
- const sdkTypesContext = {
76
+ const sdkTypesContext: SdkTypeContext = {
60
77
  operations: new Map<Type, SdkServiceMethod<SdkHttpOperation>>(),
61
- types: new Map<Type, SdkType>()
78
+ types: new Map<Type, SdkType>(),
79
+ flattenProperties: new Map<
80
+ SdkModelPropertyType,
81
+ SdkFlattenPropertyContext
82
+ >()
62
83
  };
63
84
  visitPackageTypes(context);
85
+ enrichFlattenProperties(
86
+ context,
87
+ sdkTypesContext.flattenProperties,
88
+ flattenPropertyModelMap
89
+ );
64
90
  for (const sdkModel of emitQueue) {
65
91
  switch (sdkModel.kind) {
66
92
  case "model":
@@ -126,6 +152,80 @@ export function provideSdkTypes(context: SdkContext) {
126
152
  provideContext("sdkTypes", sdkTypesContext);
127
153
  }
128
154
 
155
+ // Enrich flatten properties with their base models and conflict maps
156
+ function enrichFlattenProperties(
157
+ context: SdkContext,
158
+ propertyContextMap: Map<SdkModelPropertyType, SdkFlattenPropertyContext>,
159
+ propertyModelMap: Map<SdkModelPropertyType, SdkModelType>
160
+ ) {
161
+ // Build a map of base model to its existing properties excluding flatten properties
162
+ // To check for conflicts later
163
+ const baseModelProperties = new Map<SdkModelType, Set<string>>();
164
+ propertyModelMap.forEach((baseModel, _) => {
165
+ if (!baseModelProperties.has(baseModel)) {
166
+ const propertiesExcludedFlatten = getAllProperties(
167
+ context,
168
+ baseModel,
169
+ getAllAncestors(baseModel)
170
+ )
171
+ .filter((p) => p.flatten === false || p.flatten === undefined)
172
+ .map((p) => normalizeModelPropertyName(context, p));
173
+ baseModelProperties.set(
174
+ baseModel,
175
+ new Set<string>(propertiesExcludedFlatten)
176
+ );
177
+ }
178
+ });
179
+ for (const [flattenProperty, baseModel] of propertyModelMap) {
180
+ const flattenContext: SdkFlattenPropertyContext = {
181
+ baseModel: baseModel
182
+ };
183
+ propertyContextMap.set(flattenProperty, flattenContext);
184
+ const existingProperties = baseModelProperties.get(baseModel)!;
185
+ const conflictMap = new Map<SdkModelPropertyType, string>();
186
+ const flattenModel = flattenProperty.type;
187
+
188
+ if (flattenModel.kind !== "model") {
189
+ continue;
190
+ }
191
+ if (baseModelProperties.has(flattenModel)) {
192
+ // If the flatten model is also a base model of other flatten properties, which means it has multiple consecutive flatten operations
193
+ // Since we cannot handle the flatten transition, report warning and skip it for now
194
+ reportDiagnostic(context.program, {
195
+ code: "unsupported-flatten-transition",
196
+ format: {
197
+ propertyName: flattenProperty.name,
198
+ modelName: baseModel.name
199
+ },
200
+ target: flattenProperty.__raw!
201
+ });
202
+ }
203
+ const allFlattenProperties = getAllProperties(
204
+ context,
205
+ flattenModel,
206
+ getAllAncestors(flattenModel)
207
+ );
208
+ for (const flattenChildProperty of allFlattenProperties) {
209
+ let childPropertyName = normalizeModelPropertyName(
210
+ context,
211
+ flattenChildProperty
212
+ );
213
+ if (existingProperties.has(childPropertyName)) {
214
+ childPropertyName = normalizeName(
215
+ `${childPropertyName}_${flattenProperty.name}_${childPropertyName}`,
216
+ NameType.Property
217
+ );
218
+ conflictMap.set(flattenChildProperty, childPropertyName);
219
+ }
220
+ existingProperties.add(childPropertyName);
221
+ }
222
+ if (conflictMap.size === 0) {
223
+ continue;
224
+ }
225
+ flattenContext.conflictMap = conflictMap;
226
+ }
227
+ }
228
+
129
229
  export function getAllOperationsFromClient(
130
230
  client: SdkClientType<SdkHttpOperation>
131
231
  ) {
package/src/index.ts CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  PagingHelpers,
18
18
  PollingHelpers,
19
19
  SerializationHelpers,
20
+ SimplePollerHelpers,
20
21
  UrlTemplateHelpers
21
22
  } from "./modular/static-helpers-metadata.js";
22
23
  import {
@@ -131,6 +132,7 @@ export async function $onEmit(context: EmitContext) {
131
132
  ...SerializationHelpers,
132
133
  ...PagingHelpers,
133
134
  ...PollingHelpers,
135
+ ...SimplePollerHelpers,
134
136
  ...UrlTemplateHelpers,
135
137
  ...MultipartHelpers,
136
138
  ...CloudSettingHelpers
package/src/lib.ts CHANGED
@@ -60,6 +60,7 @@ export interface EmitterOptions {
60
60
  "enable-model-namespace"?: boolean;
61
61
  "hierarchy-client"?: boolean;
62
62
  "compatibility-mode"?: boolean;
63
+ "compatibility-lro"?: boolean;
63
64
  "experimental-extensible-enums"?: boolean;
64
65
  "clear-output-folder"?: boolean;
65
66
  "ignore-property-name-normalize"?: boolean;
@@ -281,6 +282,12 @@ export const RLCOptionsSchema: JSONSchemaType<EmitterOptions> = {
281
282
  description:
282
283
  "Whether to affect the generation of the additional property feature for the Modular client. Defaults to `false`."
283
284
  },
285
+ "compatibility-lro": {
286
+ type: "boolean",
287
+ nullable: true,
288
+ description:
289
+ "[deprecated] Whether to generate the legacy LRO interface. When `true`, we will generate legacy beginXXX and beginXXXAndWait LRO methods."
290
+ },
284
291
  "experimental-extensible-enums": {
285
292
  type: "boolean",
286
293
  nullable: true,
@@ -542,6 +549,12 @@ const libDef = {
542
549
  default: paramMessage`The parameter name ${"parameterName"} has conflicts with others and please use @clientName to rename it.`
543
550
  }
544
551
  },
552
+ "unsupported-flatten-transition": {
553
+ severity: "warning",
554
+ messages: {
555
+ default: paramMessage`The property "${"propertyName"}" in "${"modelName"}" has multiple consecutive flatten operations. Flatten transitions are not supported so consecutive transitions will be ignored.`
556
+ }
557
+ },
545
558
  "unsupported-parameter-type": {
546
559
  severity: "error",
547
560
  messages: {
@@ -589,6 +602,12 @@ const libDef = {
589
602
  messages: {
590
603
  default: paramMessage`Error traversing directory ${"directory"}: ${"error"}`
591
604
  }
605
+ },
606
+ "detected-model-name-conflict": {
607
+ severity: "warning",
608
+ messages: {
609
+ default: paramMessage`Model name conflict detected: "${"modelName"}" exists in multiple namespaces: ${"namespaces"}. Please use @clientName to rename them.`
610
+ }
592
611
  }
593
612
  },
594
613
  emitter: {
@@ -604,7 +623,7 @@ export const prettierTypeScriptOptions: Options = {
604
623
  arrowParens: "always",
605
624
  bracketSpacing: true,
606
625
  endOfLine: "lf",
607
- printWidth: 80,
626
+ printWidth: 100,
608
627
  semi: true,
609
628
  singleQuote: false,
610
629
  tabWidth: 2
@@ -31,9 +31,14 @@ import {
31
31
  SdkServiceMethod,
32
32
  SdkServiceOperation
33
33
  } from "@azure-tools/typespec-client-generator-core";
34
- import { getMethodHierarchiesMap } from "../utils/operationUtil.js";
34
+ import {
35
+ getMethodHierarchiesMap,
36
+ isTenantLevelOperation
37
+ } from "../utils/operationUtil.js";
35
38
  import { useContext } from "../contextManager.js";
36
39
  import { refkey } from "../framework/refkey.js";
40
+ import { SimplePollerHelpers } from "./static-helpers-metadata.js";
41
+ import { AzurePollingDependencies } from "./external-dependencies.js";
37
42
 
38
43
  export function buildClassicalClient(
39
44
  dpgContext: SdkContext,
@@ -117,11 +122,28 @@ export function buildClassicalClient(
117
122
  });
118
123
  }
119
124
 
120
- // TODO: We may need to generate constructor overloads at some point. Here we'd do that.
121
- const constructor = clientClass.addConstructor({
122
- docs: getDocsFromDescription(client.doc),
123
- parameters: classicalParams
124
- });
125
+ // Check if constructor overloads for subscriptionId is needed
126
+ const hasSubscriptionIdParam = classicalParams.some(
127
+ (param) => param.name.toLowerCase() === "subscriptionid"
128
+ );
129
+ const shouldSubscriptionIdOptional =
130
+ dpgContext.arm &&
131
+ hasSubscriptionIdParam &&
132
+ hasTenantLevelOperations(client, dpgContext);
133
+
134
+ let constructor;
135
+ if (shouldSubscriptionIdOptional) {
136
+ constructor = generateConstructorWithOverloads(
137
+ clientClass,
138
+ classicalParams,
139
+ client
140
+ );
141
+ } else {
142
+ constructor = clientClass.addConstructor({
143
+ docs: getDocsFromDescription(client.doc),
144
+ parameters: classicalParams
145
+ });
146
+ }
125
147
 
126
148
  const paramNames = (contextParams ?? [])
127
149
  .map((p) => p.name)
@@ -132,6 +154,11 @@ export function buildClassicalClient(
132
154
  emitterOptions,
133
155
  "azsdk-js-client"
134
156
  )}}`;
157
+ } else if (
158
+ x.toLowerCase() === "subscriptionid" &&
159
+ shouldSubscriptionIdOptional
160
+ ) {
161
+ return `subscriptionId ?? ""`;
135
162
  } else {
136
163
  return x;
137
164
  }
@@ -204,24 +231,69 @@ function generateMethod(
204
231
  context: SdkContext,
205
232
  clientType: string,
206
233
  method: [string[], SdkServiceMethod<SdkServiceOperation>]
207
- ) {
208
- const declarations = getOperationFunction(context, method, clientType);
209
- const result: MethodDeclarationStructure = {
210
- docs: declarations.docs,
211
- name: declarations.propertyName ?? declarations.name ?? "FIXME",
234
+ ): MethodDeclarationStructure[] {
235
+ const res: MethodDeclarationStructure[] = [];
236
+ const declaration = getOperationFunction(context, method, clientType);
237
+ const methodName = declaration.propertyName ?? declaration.name ?? "FIXME";
238
+ const methodParams =
239
+ declaration.parameters?.filter((p) => p.name !== "context") ?? [];
240
+ const declarationRefKey = resolveReference(refkey(method[1], "api"));
241
+ const methodParamStr = [
242
+ "this._client",
243
+ ...methodParams.map((p) => p.name)
244
+ ].join(", ");
245
+
246
+ res.push({
247
+ docs: declaration.docs,
248
+ name: methodName,
212
249
  kind: StructureKind.Method,
213
- returnType: declarations.returnType,
214
- parameters: declarations.parameters?.filter((p) => p.name !== "context"),
215
- statements: `return ${resolveReference(refkey(method[1], "api"))}(${[
216
- "this._client",
217
- ...[
218
- declarations.parameters
219
- ?.map((p) => p.name)
220
- .filter((p) => p !== "context")
221
- ]
222
- ].join(",")})`
223
- };
224
- return result;
250
+ returnType: declaration.returnType,
251
+ parameters: methodParams,
252
+ statements: `return ${declarationRefKey}(${methodParamStr})`
253
+ });
254
+
255
+ // add LRO helper methods if applicable
256
+ if (context.rlcOptions?.compatibilityLro && declaration?.isLro) {
257
+ const operationStateReference = resolveReference(
258
+ AzurePollingDependencies.OperationState
259
+ );
260
+ const simplePollerLikeReference = resolveReference(
261
+ SimplePollerHelpers.SimplePollerLike
262
+ );
263
+ const getSimplePollerReference = resolveReference(
264
+ SimplePollerHelpers.getSimplePoller
265
+ );
266
+ const returnType = declaration?.lroFinalReturnType ?? "void";
267
+ const beginName = normalizeName(`begin_${methodName}`, NameType.Method);
268
+ const beginAndWaitName = normalizeName(
269
+ `${beginName}_andWait`,
270
+ NameType.Method
271
+ );
272
+ // add begin method
273
+ res.push({
274
+ isAsync: true,
275
+ docs: [`@deprecated use ${methodName} instead`],
276
+ name: beginName,
277
+ kind: StructureKind.Method,
278
+ returnType: `Promise<${simplePollerLikeReference}<${operationStateReference}<${returnType}>, ${returnType}>>`,
279
+ parameters: methodParams,
280
+ statements: `const poller = ${declarationRefKey}(${methodParamStr});
281
+ await poller.submitted();
282
+ return ${getSimplePollerReference}(poller);`
283
+ });
284
+ // add begin and wait method
285
+ res.push({
286
+ isAsync: true,
287
+ docs: [`@deprecated use ${methodName} instead`],
288
+ name: beginAndWaitName,
289
+ kind: StructureKind.Method,
290
+ returnType: `Promise<${returnType}>`,
291
+ parameters: methodParams,
292
+ statements: `return await ${declarationRefKey}(${methodParamStr});`
293
+ });
294
+ }
295
+
296
+ return res;
225
297
  }
226
298
  function buildClientOperationGroups(
227
299
  clientMap: [string[], SdkClientType<SdkServiceOperation>],
@@ -240,8 +312,8 @@ function buildClientOperationGroups(
240
312
  const layer = 0;
241
313
  if (prefixKey === "") {
242
314
  operations.forEach((op) => {
243
- const method = generateMethod(dpgContext, clientType, [prefixes, op]);
244
- clientClass.addMethod(method);
315
+ const methods = generateMethod(dpgContext, clientType, [prefixes, op]);
316
+ clientClass.addMethods(methods);
245
317
  });
246
318
  } else {
247
319
  // The `rawGroupName` is used to any places where we need normalized name twice so we need to keep the raw as PascalCase.
@@ -323,3 +395,88 @@ function addChildClient(
323
395
  )`
324
396
  );
325
397
  }
398
+
399
+ function hasTenantLevelOperations(
400
+ client: SdkClientType<SdkServiceOperation>,
401
+ dpgContext: SdkContext
402
+ ): boolean {
403
+ const methodMap = getMethodHierarchiesMap(dpgContext, client);
404
+
405
+ for (const [_, operations] of methodMap) {
406
+ for (const op of operations) {
407
+ if (isTenantLevelOperation(op, client)) {
408
+ // Found a tenant-level operation
409
+ return true;
410
+ }
411
+ }
412
+ }
413
+
414
+ return false;
415
+ }
416
+
417
+ function generateConstructorWithOverloads(
418
+ clientClass: ClassDeclaration,
419
+ classicalParams: any[],
420
+ client: SdkClientType<SdkServiceOperation>
421
+ ) {
422
+ const filteredParams = classicalParams.filter(
423
+ (p) =>
424
+ p.name.toLowerCase() !== "subscriptionid" &&
425
+ p.name.toLowerCase() !== "options"
426
+ );
427
+
428
+ const clientConstructor = clientClass.addConstructor({
429
+ docs: getDocsFromDescription(client.doc),
430
+ parameters: [
431
+ ...filteredParams,
432
+ {
433
+ name: "subscriptionIdOrOptions",
434
+ type: `string | ${getClassicalClientName(client)}OptionalParams`,
435
+ hasQuestionToken: true
436
+ },
437
+ {
438
+ name: "options",
439
+ type: `${getClassicalClientName(client)}OptionalParams`,
440
+ hasQuestionToken: true
441
+ }
442
+ ]
443
+ });
444
+
445
+ clientConstructor.addOverload({
446
+ parameters: [
447
+ ...filteredParams,
448
+ {
449
+ name: "options",
450
+ type: `${getClassicalClientName(client)}OptionalParams`,
451
+ hasQuestionToken: true
452
+ }
453
+ ]
454
+ });
455
+
456
+ clientConstructor.addOverload({
457
+ parameters: [
458
+ ...filteredParams,
459
+ ...classicalParams.filter(
460
+ (p) => p.name.toLowerCase() === "subscriptionid"
461
+ ),
462
+ {
463
+ name: "options",
464
+ type: `${getClassicalClientName(client)}OptionalParams`,
465
+ hasQuestionToken: true
466
+ }
467
+ ]
468
+ });
469
+
470
+ clientConstructor.addStatements([
471
+ `let subscriptionId: string | undefined;`,
472
+ ``,
473
+ `if (typeof subscriptionIdOrOptions === "string") {`,
474
+ ` subscriptionId = subscriptionIdOrOptions;`,
475
+ `} else if (typeof subscriptionIdOrOptions === "object") {`,
476
+ ` options = subscriptionIdOrOptions;`,
477
+ `}`,
478
+ `options = options ?? {};`
479
+ ]);
480
+
481
+ return clientConstructor;
482
+ }
@@ -10,7 +10,6 @@ import {
10
10
  } from "./static-helpers-metadata.js";
11
11
  import {
12
12
  SdkClientType,
13
- SdkContext,
14
13
  SdkServiceOperation
15
14
  } from "@azure-tools/typespec-client-generator-core";
16
15
  import { getModularClientOptions } from "../utils/clientUtils.js";
@@ -19,6 +18,8 @@ import { join } from "path/posix";
19
18
  import { useContext } from "../contextManager.js";
20
19
  import { reportDiagnostic } from "../lib.js";
21
20
  import { NoTarget } from "@typespec/compiler";
21
+ import { isLroOnlyOperation } from "./helpers/operationHelpers.js";
22
+ import { SdkContext } from "../utils/interfaces.js";
22
23
 
23
24
  export function buildRootIndex(
24
25
  context: SdkContext,
@@ -55,6 +56,14 @@ export function buildRootIndex(
55
56
  }
56
57
 
57
58
  exportClassicalClient(client, rootIndexFile, subfolder ?? "");
59
+ exportSimplePollerLike(
60
+ context,
61
+ clientMap,
62
+ rootIndexFile,
63
+ project,
64
+ srcPath,
65
+ subfolder
66
+ );
58
67
  exportRestoreHelpers(
59
68
  rootIndexFile,
60
69
  project,
@@ -188,6 +197,41 @@ function addExportsToRootIndexFile(
188
197
  }
189
198
  }
190
199
 
200
+ function exportSimplePollerLike(
201
+ context: SdkContext,
202
+ clientMap: [string[], SdkClientType<SdkServiceOperation>],
203
+ indexFile: SourceFile,
204
+ project: Project,
205
+ srcPath: string,
206
+ subfolder: string = "",
207
+ isTopLevel: boolean = false
208
+ ) {
209
+ const [_, client] = clientMap;
210
+
211
+ const methodMap = getMethodHierarchiesMap(context, client);
212
+ const hasLro = Array.from(methodMap.values()).some((operations) => {
213
+ return operations.some(isLroOnlyOperation);
214
+ });
215
+ if (!hasLro || context.rlcOptions?.compatibilityLro !== true) {
216
+ return;
217
+ }
218
+ const helperFile = project.getSourceFile(
219
+ `${srcPath}/${
220
+ subfolder && subfolder !== "" ? subfolder + "/" : ""
221
+ }static-helpers/simplePollerHelpers.ts`
222
+ );
223
+ if (!helperFile) {
224
+ return;
225
+ }
226
+ const moduleSpecifier = `./${
227
+ isTopLevel && subfolder && subfolder !== "" ? subfolder + "/" : ""
228
+ }static-helpers/simplePollerHelpers.js`;
229
+ indexFile.addExportDeclaration({
230
+ moduleSpecifier,
231
+ namedExports: ["SimplePollerLike"]
232
+ });
233
+ }
234
+
191
235
  function exportRestoreHelpers(
192
236
  indexFile: SourceFile,
193
237
  project: Project,
@@ -381,6 +425,14 @@ export function buildSubClientIndexFile(
381
425
  }
382
426
 
383
427
  exportClassicalClient(client, subClientIndexFile, subfolder ?? "", true);
428
+ exportSimplePollerLike(
429
+ context,
430
+ clientMap,
431
+ subClientIndexFile,
432
+ project,
433
+ srcPath,
434
+ subfolder
435
+ );
384
436
  exportRestoreHelpers(
385
437
  subClientIndexFile,
386
438
  project,