@azure-tools/typespec-ts 0.48.1 → 0.49.0-alpha.20260203.1

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 (97) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +2 -1
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/modular/buildClientContext.d.ts.map +1 -1
  6. package/dist/src/modular/buildClientContext.js +6 -25
  7. package/dist/src/modular/buildClientContext.js.map +1 -1
  8. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  9. package/dist/src/modular/buildOperations.js +1 -1
  10. package/dist/src/modular/buildOperations.js.map +1 -1
  11. package/dist/src/modular/buildProjectFiles.d.ts.map +1 -1
  12. package/dist/src/modular/buildProjectFiles.js +13 -10
  13. package/dist/src/modular/buildProjectFiles.js.map +1 -1
  14. package/dist/src/modular/buildRestorePoller.d.ts.map +1 -1
  15. package/dist/src/modular/buildRestorePoller.js +9 -2
  16. package/dist/src/modular/buildRestorePoller.js.map +1 -1
  17. package/dist/src/modular/emitModels.d.ts.map +1 -1
  18. package/dist/src/modular/emitModels.js +18 -4
  19. package/dist/src/modular/emitModels.js.map +1 -1
  20. package/dist/src/modular/emitSamples.d.ts.map +1 -1
  21. package/dist/src/modular/emitSamples.js +19 -1
  22. package/dist/src/modular/emitSamples.js.map +1 -1
  23. package/dist/src/modular/helpers/clientHelpers.d.ts +1 -0
  24. package/dist/src/modular/helpers/clientHelpers.d.ts.map +1 -1
  25. package/dist/src/modular/helpers/clientHelpers.js +28 -8
  26. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  27. package/dist/src/modular/helpers/operationHelpers.d.ts +2 -2
  28. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  29. package/dist/src/modular/helpers/operationHelpers.js +53 -9
  30. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  31. package/dist/src/modular/helpers/typeHelpers.js +1 -1
  32. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  33. package/dist/src/modular/serialization/buildDeserializerFunction.js +5 -1
  34. package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
  35. package/dist/src/modular/serialization/buildSerializerFunction.js +5 -1
  36. package/dist/src/modular/serialization/buildSerializerFunction.js.map +1 -1
  37. package/dist/src/modular/serialization/serializeUtils.d.ts.map +1 -1
  38. package/dist/src/modular/serialization/serializeUtils.js +1 -0
  39. package/dist/src/modular/serialization/serializeUtils.js.map +1 -1
  40. package/dist/src/modular/type-expressions/get-type-expression.js +1 -1
  41. package/dist/src/modular/type-expressions/get-type-expression.js.map +1 -1
  42. package/dist/src/transform/transform.d.ts.map +1 -1
  43. package/dist/src/transform/transform.js +10 -10
  44. package/dist/src/transform/transform.js.map +1 -1
  45. package/dist/src/transform/transformPaths.js +1 -1
  46. package/dist/src/transform/transformPaths.js.map +1 -1
  47. package/dist/src/transform/transformSchemas.d.ts.map +1 -1
  48. package/dist/src/transform/transformSchemas.js +4 -4
  49. package/dist/src/transform/transformSchemas.js.map +1 -1
  50. package/dist/src/transform/transfromRLCOptions.d.ts +1 -1
  51. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  52. package/dist/src/transform/transfromRLCOptions.js +25 -24
  53. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  54. package/dist/src/utils/clientUtils.d.ts +1 -1
  55. package/dist/src/utils/clientUtils.d.ts.map +1 -1
  56. package/dist/src/utils/clientUtils.js +47 -15
  57. package/dist/src/utils/clientUtils.js.map +1 -1
  58. package/dist/src/utils/crossLanguageDef.d.ts.map +1 -1
  59. package/dist/src/utils/crossLanguageDef.js +9 -3
  60. package/dist/src/utils/crossLanguageDef.js.map +1 -1
  61. package/dist/src/utils/interfaces.d.ts +2 -1
  62. package/dist/src/utils/interfaces.d.ts.map +1 -1
  63. package/dist/src/utils/modelUtils.d.ts +1 -1
  64. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  65. package/dist/src/utils/modelUtils.js +14 -9
  66. package/dist/src/utils/modelUtils.js.map +1 -1
  67. package/dist/src/utils/operationUtil.d.ts +1 -1
  68. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  69. package/dist/src/utils/operationUtil.js +7 -4
  70. package/dist/src/utils/operationUtil.js.map +1 -1
  71. package/dist/tsconfig.tsbuildinfo +1 -1
  72. package/package.json +7 -7
  73. package/src/index.ts +2 -0
  74. package/src/modular/buildClientContext.ts +6 -26
  75. package/src/modular/buildOperations.ts +0 -1
  76. package/src/modular/buildProjectFiles.ts +19 -16
  77. package/src/modular/buildRestorePoller.ts +9 -2
  78. package/src/modular/emitModels.ts +16 -3
  79. package/src/modular/emitSamples.ts +29 -1
  80. package/src/modular/helpers/clientHelpers.ts +33 -11
  81. package/src/modular/helpers/operationHelpers.ts +60 -16
  82. package/src/modular/helpers/typeHelpers.ts +1 -1
  83. package/src/modular/serialization/buildDeserializerFunction.ts +5 -1
  84. package/src/modular/serialization/buildSerializerFunction.ts +5 -1
  85. package/src/modular/serialization/serializeUtils.ts +1 -0
  86. package/src/modular/type-expressions/get-type-expression.ts +1 -1
  87. package/src/transform/transform.ts +5 -2
  88. package/src/transform/transformPaths.ts +1 -1
  89. package/src/transform/transformSchemas.ts +4 -1
  90. package/src/transform/transfromRLCOptions.ts +45 -24
  91. package/src/utils/clientUtils.ts +55 -14
  92. package/src/utils/crossLanguageDef.ts +8 -0
  93. package/src/utils/interfaces.ts +2 -1
  94. package/src/utils/modelUtils.ts +20 -6
  95. package/src/utils/operationUtil.ts +11 -3
  96. package/static/static-helpers/pagingHelpers.ts +32 -6
  97. package/static/static-helpers/pollingHelpers.ts +27 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.48.1",
3
+ "version": "0.49.0-alpha.20260203.1",
4
4
  "description": "An experimental TypeSpec emitter for TypeScript RLC",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -18,15 +18,15 @@
18
18
  "license": "MIT",
19
19
  "devDependencies": {
20
20
  "@azure-rest/core-client": "^2.3.1",
21
- "@typespec/http-specs": "0.1.0-alpha.31-dev.1",
22
- "@typespec/spector": "0.1.0-alpha.23-dev.0",
21
+ "@typespec/http-specs": "0.1.0-alpha.32-dev.1",
22
+ "@typespec/spector": "0.1.0-alpha.23-dev.1",
23
23
  "@typespec/spec-api": "0.1.0-alpha.13-dev.0",
24
24
  "@typespec/tspd": "0.73.3",
25
- "@azure-tools/azure-http-specs": "0.1.0-alpha.37-dev.0",
25
+ "@azure-tools/azure-http-specs": "0.1.0-alpha.37-dev.1",
26
26
  "@azure-tools/typespec-autorest": "^0.64.0",
27
27
  "@azure-tools/typespec-azure-core": "^0.64.0",
28
28
  "@azure-tools/typespec-azure-resource-manager": "^0.64.0",
29
- "@azure-tools/typespec-client-generator-core": "^0.64.1",
29
+ "@azure-tools/typespec-client-generator-core": "^0.64.4",
30
30
  "@azure/abort-controller": "^2.1.2",
31
31
  "@azure/core-auth": "^1.6.0",
32
32
  "@azure/core-lro": "^3.1.0",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "peerDependencies": {
67
67
  "@azure-tools/typespec-azure-core": "^0.64.0",
68
- "@azure-tools/typespec-client-generator-core": "^0.64.1",
68
+ "@azure-tools/typespec-client-generator-core": "^0.64.4",
69
69
  "@typespec/compiler": "^1.8.0",
70
70
  "@typespec/http": "^1.8.0",
71
71
  "@typespec/rest": "^0.78.0",
@@ -73,7 +73,7 @@
73
73
  "@typespec/xml": "^0.78.0"
74
74
  },
75
75
  "dependencies": {
76
- "@azure-tools/rlc-common": "^0.48.1",
76
+ "@azure-tools/rlc-common": "0.49.0-alpha.20260203.1",
77
77
  "fast-xml-parser": "^4.5.0",
78
78
  "fs-extra": "^11.1.0",
79
79
  "lodash": "^4.17.21",
package/src/index.ts CHANGED
@@ -82,6 +82,7 @@ import { buildRestorePoller } from "./modular/buildRestorePoller.js";
82
82
  import { buildSubpathIndexFile } from "./modular/buildSubpathIndex.js";
83
83
  import {
84
84
  createSdkContext,
85
+ listAllServiceNamespaces,
85
86
  SdkClientType,
86
87
  SdkServiceOperation
87
88
  } from "@azure-tools/typespec-client-generator-core";
@@ -192,6 +193,7 @@ export async function $onEmit(context: EmitContext) {
192
193
  const generationPathDetail: GenerationDirDetail =
193
194
  await calculateGenerationDir();
194
195
  dpgContext.generationPathDetail = generationPathDetail;
196
+ dpgContext.allServiceNamespaces = listAllServiceNamespaces(dpgContext);
195
197
  const options: RLCOptions = transformRLCOptions(emitterOptions, dpgContext);
196
198
  emitterOptions["is-modular-library"] = options.isModularLibrary;
197
199
  emitterOptions["generate-sample"] = options.generateSample;
@@ -81,8 +81,7 @@ export function buildClientContext(
81
81
  // Get all client parameters (both required and optional) for the interface
82
82
  const requiredInterfaceProperties = getClientParameters(client, dpgContext, {
83
83
  onClientOnly: false,
84
- requiredOnly: true,
85
- apiVersionAsRequired: true
84
+ requiredOnly: true
86
85
  })
87
86
  .filter((p) => {
88
87
  const clientParamName = getClientParameterName(p);
@@ -239,7 +238,7 @@ export function buildClientContext(
239
238
  `);
240
239
  }
241
240
 
242
- let apiVersionPolicyStatement = `clientContext.pipeline.removePolicy({ name: "ApiVersionPolicy" });`;
241
+ let apiVersionStatement = ``;
243
242
  const endpointParameter = getClientParameters(client, dpgContext, {
244
243
  onClientOnly: false,
245
244
  requiredOnly: true,
@@ -255,39 +254,20 @@ export function buildClientContext(
255
254
  const apiVersionInEndpoint =
256
255
  templateArguments && templateArguments.find((p) => p.isApiVersionParam);
257
256
  if (!apiVersionInEndpoint && apiVersionParam.clientDefaultValue) {
258
- apiVersionPolicyStatement += `const ${apiVersionParamName} = options.${apiVersionParamName} ?? "${apiVersionParam.clientDefaultValue}";`;
259
- }
260
-
261
- if (apiVersionParam.kind === "method") {
262
- apiVersionPolicyStatement += `
263
- clientContext.pipeline.addPolicy({
264
- name: 'ClientApiVersionPolicy',
265
- sendRequest: (req, next) => {
266
- // Use the apiVersion defined in request url directly
267
- // Append one if there is no apiVersion and we have one at client options
268
- const url = new URL(req.url);
269
- if (!url.searchParams.get("api-version")) {
270
- req.url = \`\${req.url}\${
271
- Array.from(url.searchParams.keys()).length > 0 ? "&" : "?"
272
- }api-version=\${${getClientParameterName(apiVersionParam)}}\`;
273
- }
274
-
275
- return next(req);
276
- },
277
- });`;
257
+ apiVersionStatement += `const ${apiVersionParamName} = options.${apiVersionParamName};`;
278
258
  }
279
259
  } else if (isAzurePackage(emitterOptions)) {
280
- apiVersionPolicyStatement += `
260
+ apiVersionStatement += `
281
261
  if (options.apiVersion) {
282
262
  logger.warning("This client does not support client api-version, please change it at the operation level");
283
263
  }`;
284
264
  } else {
285
- apiVersionPolicyStatement += `
265
+ apiVersionStatement += `
286
266
  if (options.apiVersion) {
287
267
  console.warn("This client does not support client api-version, please change it at the operation level");
288
268
  }`;
289
269
  }
290
- factoryFunction.addStatements(apiVersionPolicyStatement);
270
+ factoryFunction.addStatements(apiVersionStatement);
291
271
 
292
272
  const contextRequiredParam = requiredParams.filter(
293
273
  (p) =>
@@ -84,7 +84,6 @@ export function buildOperationFiles(
84
84
  );
85
85
  const sendOperationDeclaration = getSendPrivateFunction(
86
86
  dpgContext,
87
- client,
88
87
  [prefixes, op],
89
88
  clientType
90
89
  );
@@ -35,23 +35,26 @@ function buildExportsForMultiClient(
35
35
  delete packageInfo.exports["./api"];
36
36
  }
37
37
  if (emitterOptions.options.hierarchyClient) {
38
- for (const flattenedClient of clientMap) {
39
- const { subfolder } = getModularClientOptions(flattenedClient);
40
- const client = flattenedClient[1];
41
- const methodMap = getMethodHierarchiesMap(context, client);
42
- for (const [prefixKey, _] of methodMap) {
43
- const prefixes = prefixKey.split("/");
44
- if (prefixKey === "") {
45
- continue;
38
+ // TODO: support api subpath exports for multi-service. Skip for now. https://github.com/Azure/autorest.typescript/issues/3717
39
+ if (!emitterOptions.options.isMultiService) {
40
+ for (const flattenedClient of clientMap) {
41
+ const { subfolder } = getModularClientOptions(flattenedClient);
42
+ const client = flattenedClient[1];
43
+ const methodMap = getMethodHierarchiesMap(context, client);
44
+ for (const [prefixKey, _] of methodMap) {
45
+ const prefixes = prefixKey.split("/");
46
+ if (prefixKey === "") {
47
+ continue;
48
+ }
49
+ const subApiPath = `api/${getClassicalLayerPrefix(
50
+ prefixes,
51
+ NameType.File,
52
+ "/"
53
+ )}`;
54
+ packageInfo.exports[
55
+ `./${subfolder ? subfolder + "/" : ""}${subApiPath}`
56
+ ] = `src/${subfolder ? subfolder + "/" : ""}${subApiPath}/index.ts`;
46
57
  }
47
- const subApiPath = `api/${getClassicalLayerPrefix(
48
- prefixes,
49
- NameType.File,
50
- "/"
51
- )}`;
52
- packageInfo.exports[
53
- `./${subfolder ? subfolder + "/" : ""}${subApiPath}`
54
- ] = `src/${subfolder ? subfolder + "/" : ""}${subApiPath}/index.ts`;
55
58
  }
56
59
  }
57
60
  delete packageInfo.exports["./models"];
@@ -111,6 +111,7 @@ export function buildRestorePoller(
111
111
  \`Please ensure the operation is in this client! We can't find its deserializeHelper for \${sourceOperation?.name}.\`
112
112
  );
113
113
  }
114
+ const apiVersion = getApiVersionFromUrl(initialRequestUrl);
114
115
  return ${resolveReference(PollingHelpers.GetLongRunningPoller)}(
115
116
  (client as any)["_client"] ?? client,
116
117
  deserializeHelper as (result: TResponse) => Promise<TResult>,
@@ -120,7 +121,8 @@ export function buildRestorePoller(
120
121
  abortSignal: options?.abortSignal,
121
122
  resourceLocationConfig,
122
123
  restoreFrom: serializedState,
123
- initialRequestUrl
124
+ initialRequestUrl,
125
+ apiVersion,
124
126
  }
125
127
  );
126
128
  }
@@ -209,7 +211,12 @@ export function buildRestorePoller(
209
211
  function getPathFromMapKey(mapKey: string): string {
210
212
  const pathStart = mapKey.indexOf("/");
211
213
  return mapKey.slice(pathStart);
212
- }
214
+ }
215
+
216
+ function getApiVersionFromUrl(urlStr: string): string | undefined {
217
+ const url = new URL(urlStr);
218
+ return url.searchParams.get("api-version") ?? undefined;
219
+ }
213
220
  `;
214
221
  restorePollerFile.addStatements(restorePollerHelperContent);
215
222
  }
@@ -216,6 +216,10 @@ function emitType(context: SdkContext, type: SdkType, sourceFile: SourceFile) {
216
216
  return;
217
217
  }
218
218
  const apiVersionEnumOnly = type.usage === UsageFlags.ApiVersionEnum;
219
+ // Skip known api version enums for multi-service scenarios as users are not allowed to set api versions
220
+ if (apiVersionEnumOnly && context.rlcOptions?.isMultiService) {
221
+ return;
222
+ }
219
223
  const inputUsage = (type.usage & UsageFlags.Input) === UsageFlags.Input;
220
224
  const outputUsage = (type.usage & UsageFlags.Output) === UsageFlags.Output;
221
225
  const exceptionUsage =
@@ -266,6 +270,10 @@ function emitType(context: SdkContext, type: SdkType, sourceFile: SourceFile) {
266
270
  }
267
271
 
268
272
  export function getApiVersionEnum(context: SdkContext) {
273
+ // Skip api version enum for multi-service scenarios since each service may have different versions
274
+ if (context.rlcOptions?.isMultiService) {
275
+ return;
276
+ }
269
277
  const apiVersionEnum = context.sdkPackage.enums.find(
270
278
  (e) => e.usage === UsageFlags.ApiVersionEnum
271
279
  );
@@ -293,9 +301,6 @@ export function getModelNamespaces(
293
301
  context: SdkContext,
294
302
  model: SdkType
295
303
  ): string[] {
296
- const deepestNamespace = getNamespaceFullName(
297
- listAllServiceNamespaces(context)[0]!
298
- );
299
304
  if (
300
305
  model.kind === "model" ||
301
306
  model.kind === "enum" ||
@@ -312,6 +317,14 @@ export function getModelNamespaces(
312
317
  return [];
313
318
  }
314
319
  const segments = model.namespace.split(".");
320
+ // Keep full namespace segments if multiple services are present because there isn't a root namespace to trim
321
+ if (context.rlcOptions?.isMultiService) {
322
+ return segments;
323
+ }
324
+
325
+ const allServiceNamespaces =
326
+ context.allServiceNamespaces ?? listAllServiceNamespaces(context);
327
+ const deepestNamespace = getNamespaceFullName(allServiceNamespaces[0]!);
315
328
  const rootNamespace = deepestNamespace.split(".") ?? [];
316
329
  if (segments.length > rootNamespace.length) {
317
330
  while (segments[0] === rootNamespace[0]) {
@@ -38,7 +38,12 @@ import {
38
38
  ServiceOperation
39
39
  } from "../utils/operationUtil.js";
40
40
  import { getSubscriptionId } from "../transform/transfromRLCOptions.js";
41
- import { getClientParametersDeclaration } from "./helpers/clientHelpers.js";
41
+ import {
42
+ getClientParametersDeclaration,
43
+ getClientParameters,
44
+ hasDefaultValue,
45
+ getClientParameterName
46
+ } from "./helpers/clientHelpers.js";
42
47
  import { getOperationFunction } from "./helpers/operationHelpers.js";
43
48
  import { ModelOverrideOptions } from "./serialization/serializeUtils.js";
44
49
 
@@ -298,6 +303,12 @@ function prepareExampleParameters(
298
303
  // TODO: blocked by TCGC issue: https://github.com/Azure/typespec-azure/issues/1419
299
304
  // refine this to support generic client-level parameters once resolved
300
305
  const result: ExampleValue[] = [];
306
+
307
+ // Get the raw SDK parameters to check for default values
308
+ const rawClientParams = getClientParameters(topLevelClient, dpgContext, {
309
+ onClientOnly: true
310
+ });
311
+
301
312
  const clientParams = getClientParametersDeclaration(
302
313
  topLevelClient,
303
314
  dpgContext,
@@ -306,11 +317,27 @@ function prepareExampleParameters(
306
317
  }
307
318
  );
308
319
 
320
+ // Helper to check if a parameter has a default value
321
+ const hasParamDefaultValue = (paramName: string) => {
322
+ const rawParam = rawClientParams.find((p) => {
323
+ return getClientParameterName(p) === paramName;
324
+ });
325
+
326
+ if (!rawParam) return false;
327
+
328
+ return hasDefaultValue(rawParam);
329
+ };
330
+
309
331
  for (const param of clientParams) {
310
332
  if (param.name === "options" || param.name === "credential") {
311
333
  continue;
312
334
  }
313
335
 
336
+ // Skip parameters that have default values - they are truly optional
337
+ if (hasParamDefaultValue(param.name)) {
338
+ continue;
339
+ }
340
+
314
341
  const exampleValue: ExampleValue = {
315
342
  name: param.name === "endpointParam" ? "endpoint" : param.name,
316
343
  value: getEnvironmentVariableName(
@@ -517,6 +544,7 @@ function getParameterValue(
517
544
  switch (value.kind) {
518
545
  case "string": {
519
546
  switch (value.type.kind) {
547
+ case "plainDate":
520
548
  case "utcDateTime":
521
549
  retValue = `new Date("${value.value}")`;
522
550
  break;
@@ -40,6 +40,28 @@ type SdkParameter =
40
40
  | SdkCredentialParameter
41
41
  | SdkHttpParameter;
42
42
 
43
+ export function hasDefaultValue(p: SdkParameter) {
44
+ if (
45
+ p.clientDefaultValue ||
46
+ p.__raw?.defaultValue ||
47
+ p.type.kind === "constant"
48
+ ) {
49
+ return true;
50
+ }
51
+
52
+ // Special case for endpoint parameters with template arguments that have default values
53
+ if (p.type.kind === "endpoint" && p.type.templateArguments[0]) {
54
+ const templateArg = p.type.templateArguments[0];
55
+ return !!(
56
+ templateArg.clientDefaultValue ||
57
+ templateArg.__raw?.defaultValue ||
58
+ templateArg.type?.kind === "constant"
59
+ );
60
+ }
61
+
62
+ return false;
63
+ }
64
+
43
65
  export function getClientParameters(
44
66
  client: SdkClientType<SdkServiceOperation>,
45
67
  dpgContext: SdkContext,
@@ -70,23 +92,22 @@ export function getClientParameters(
70
92
  }
71
93
  }
72
94
 
73
- const hasDefaultValue = (p: SdkParameter) =>
74
- p.clientDefaultValue || p.__raw?.defaultValue || p.type.kind === "constant";
75
95
  const isRequired = (p: SdkParameter) =>
76
96
  // Special case: when apiVersionAsRequired is true, apiVersion should always be considered required
77
97
  (options.apiVersionAsRequired && p.isApiVersionParam) ||
78
- (!p.optional &&
79
- !hasDefaultValue(p) &&
80
- !(
81
- p.type.kind === "endpoint" &&
82
- p.type.templateArguments[0] &&
83
- hasDefaultValue(p.type.templateArguments[0])
84
- ));
85
- const isOptional = (p: SdkParameter) => p.optional || hasDefaultValue(p);
98
+ (!p.optional && !hasDefaultValue(p));
99
+ const isOptional = (p: SdkParameter) =>
100
+ p.optional ||
101
+ p.clientDefaultValue ||
102
+ p.__raw?.defaultValue ||
103
+ p.type.kind === "constant";
86
104
  const skipCredentials = (p: SdkParameter) => p.kind !== "credential";
87
105
  const skipMethodParam = (p: SdkParameter) => p.kind !== "method";
88
106
  const armSpecific = (p: SdkParameter) =>
89
107
  !(p.kind === "endpoint" && dpgContext.arm);
108
+ // Skip apiVersion parameter when it's multi-service (each service has its own default apiVersion)
109
+ const skipApiVersionOnMultiService = (p: SdkParameter) =>
110
+ !(dpgContext.rlcOptions?.isMultiService && p.isApiVersionParam);
90
111
  const filters = [
91
112
  options.requiredOnly ? isRequired : undefined,
92
113
  dpgContext.rlcOptions?.addCredentials === false
@@ -94,7 +115,8 @@ export function getClientParameters(
94
115
  : undefined,
95
116
  options.optionalOnly ? isOptional : undefined,
96
117
  options.onClientOnly ? skipMethodParam : undefined,
97
- options.skipArmSpecific ? undefined : armSpecific
118
+ options.skipArmSpecific ? undefined : armSpecific,
119
+ skipApiVersionOnMultiService
98
120
  ];
99
121
  const params = clientParams.filter((p) =>
100
122
  filters.every((filter) => !filter || filter(p))
@@ -70,7 +70,6 @@ import {
70
70
  isHttpMetadata,
71
71
  isReadOnly,
72
72
  SdkBodyParameter,
73
- SdkClientType,
74
73
  SdkConstantType,
75
74
  SdkEnumType,
76
75
  SdkHttpOperation,
@@ -90,7 +89,6 @@ import { isExtensibleEnum } from "../type-expressions/get-enum-expression.js";
90
89
 
91
90
  export function getSendPrivateFunction(
92
91
  dpgContext: SdkContext,
93
- client: SdkClientType<SdkHttpOperation>,
94
92
  method: [string[], ServiceOperation],
95
93
  clientType: string
96
94
  ): OptionalKind<FunctionDeclarationStructure> {
@@ -114,12 +112,6 @@ export function getSendPrivateFunction(
114
112
  const operationPath = operation.operation.path;
115
113
  const operationMethod = operation.operation.verb.toLowerCase();
116
114
  const optionalParamName = getOptionalParamsName(parameters);
117
- const hasQueryApiVersion = operation.operation.parameters.some(
118
- (p) => p.onClient && p.kind === "query" && p.isApiVersionParam
119
- );
120
- const hasClientApiVersion = client.clientInitialization.parameters.some(
121
- (p) => p.isApiVersionParam && p.onClient && p.kind === "method"
122
- );
123
115
  const statements: string[] = [];
124
116
  let pathStr = `"${operationPath}"`;
125
117
  const urlTemplateParams = [
@@ -134,11 +126,6 @@ export function getSendPrivateFunction(
134
126
  });`);
135
127
  pathStr = "path";
136
128
  }
137
- if (hasClientApiVersion && !hasQueryApiVersion) {
138
- statements.push(
139
- `context.pipeline.removePolicy({ name: "ClientApiVersionPolicy"});`
140
- );
141
- }
142
129
 
143
130
  statements.push(
144
131
  `return context.path(${pathStr}).${operationMethod}({...${resolveReference(dependencies.operationOptionsToRequestParameters)}(${optionalParamName}), ${getHeaderAndBodyParameters(
@@ -684,9 +671,11 @@ function getLroOnlyOperationFunction(
684
671
  const resourceLocationConfig =
685
672
  lroMetadata?.finalStateVia &&
686
673
  allowedFinalLocation.includes(lroMetadata?.finalStateVia)
687
- ? `resourceLocationConfig: "${lroMetadata?.finalStateVia}"`
674
+ ? `resourceLocationConfig: "${lroMetadata?.finalStateVia}",`
688
675
  : "";
676
+ const apiVersion = getApiVersionExpression(context, operation);
689
677
  const statements: string[] = [];
678
+
690
679
  statements.push(`
691
680
 
692
681
  return ${getLongRunningPollerReference}(context, _${name}Deserialize, ${getExpectedStatuses(
@@ -698,6 +687,7 @@ function getLroOnlyOperationFunction(
698
687
  .map((p) => p.name)
699
688
  .join(", ")}),
700
689
  ${resourceLocationConfig}
690
+ ${apiVersion ? `apiVersion: ${apiVersion}` : ""}
701
691
  }) as ${pollerLikeReference}<${operationStateReference}<${
702
692
  returnType.type
703
693
  }>, ${returnType.type}>;
@@ -725,6 +715,9 @@ function getLroAndPagingOperationFunction(
725
715
 
726
716
  const returnType = buildLroPagingReturnType(context, operation);
727
717
 
718
+ // Get apiVersion expression for both LRO poller and paging options
719
+ const apiVersion = getApiVersionExpression(context, operation);
720
+
728
721
  // Build paging options from metadata
729
722
  const pagingOptions = [
730
723
  operation.response.resultSegments &&
@@ -732,7 +725,8 @@ function getLroAndPagingOperationFunction(
732
725
  operation.pagingMetadata.nextLinkSegments &&
733
726
  `nextLinkName: "${operation.pagingMetadata.nextLinkSegments.map((p) => p.name).join(".")}"`,
734
727
  operation.pagingMetadata.nextLinkVerb !== "GET" &&
735
- `nextLinkMethod: "${operation.pagingMetadata.nextLinkVerb}"`
728
+ `nextLinkMethod: "${operation.pagingMetadata.nextLinkVerb}"`,
729
+ apiVersion && `apiVersion: ${apiVersion}`
736
730
  ].filter(Boolean);
737
731
 
738
732
  // Build LRO resource location config
@@ -745,7 +739,7 @@ function getLroAndPagingOperationFunction(
745
739
  const resourceLocationConfig =
746
740
  operation.lroMetadata?.finalStateVia &&
747
741
  allowedLocations.includes(operation.lroMetadata.finalStateVia)
748
- ? `resourceLocationConfig: "${operation.lroMetadata.finalStateVia}"`
742
+ ? `resourceLocationConfig: "${operation.lroMetadata.finalStateVia}",`
749
743
  : "";
750
744
 
751
745
  // Resolve references
@@ -784,6 +778,7 @@ function getLroAndPagingOperationFunction(
784
778
  abortSignal: ${optionalParamName}?.abortSignal,
785
779
  getInitialResponse: () => _${name}Send(${paramList}),
786
780
  ${resourceLocationConfig}
781
+ ${apiVersion ? `apiVersion: ${apiVersion}` : ""}
787
782
  }) as ${refs.pollerLike}<${refs.operationState}<${refs.pathResponse}>, ${refs.pathResponse}>;
788
783
 
789
784
  return ${refs.buildPaging}(
@@ -887,6 +882,8 @@ function getPagingOnlyOperationFunction(
887
882
  // Check for nextLinkVerb from TCGC pagingMetadata (supports @Legacy.nextLinkVerb decorator)
888
883
  const nextLinkMethod = operation.pagingMetadata.nextLinkVerb;
889
884
 
885
+ const apiVersion = getApiVersionExpression(context, operation);
886
+
890
887
  if (itemName) {
891
888
  options.push(`itemName: "${itemName}"`);
892
889
  }
@@ -896,6 +893,9 @@ function getPagingOnlyOperationFunction(
896
893
  if (nextLinkMethod && nextLinkMethod !== "GET") {
897
894
  options.push(`nextLinkMethod: "${nextLinkMethod}"`);
898
895
  }
896
+ if (apiVersion) {
897
+ options.push(`apiVersion: ${apiVersion}`);
898
+ }
899
899
  statements.push(
900
900
  `return ${buildPagedAsyncIteratorReference}(
901
901
  context,
@@ -1151,6 +1151,15 @@ export function getParameterMap(
1151
1151
  return `"${serializedName}": ${getConstantValue(param.type)}`;
1152
1152
  }
1153
1153
 
1154
+ // Special case for api-version parameters with default values
1155
+ if (param.isApiVersionParam && param.clientDefaultValue) {
1156
+ // For multi-service, use only the default value (don't reference context.apiVersion)
1157
+ if (context.rlcOptions?.isMultiService) {
1158
+ return `"${serializedName}": "${param.clientDefaultValue}"`;
1159
+ }
1160
+ return `"${serializedName}": ${param.onClient ? "context." : ""}${param.name} ?? "${param.clientDefaultValue}"`;
1161
+ }
1162
+
1154
1163
  if (hasCollectionFormatInfo(param.kind, (param as any).collectionFormat)) {
1155
1164
  return getCollectionFormatForParam(
1156
1165
  context,
@@ -1722,6 +1731,9 @@ export function serializeRequestValue(
1722
1731
  ? `!${clientValue}? ${clientValue}: `
1723
1732
  : "";
1724
1733
  switch (type.kind) {
1734
+ case "plainDate":
1735
+ // plainDate always uses ISO8601 format (YYYY-MM-DD)
1736
+ return `${nullOrUndefinedPrefix}${clientValue}.toISOString().split('T')[0]`;
1725
1737
  case "utcDateTime":
1726
1738
  switch (type.encode ?? format) {
1727
1739
  case "rfc7231":
@@ -1849,6 +1861,9 @@ export function deserializeResponseValue(
1849
1861
  ? `!${restValue}? ${restValue}: `
1850
1862
  : "";
1851
1863
  switch (type.kind) {
1864
+ case "plainDate":
1865
+ // plainDate deserializes from YYYY-MM-DD string to Date
1866
+ return `${nullOrUndefinedPrefix} new Date(${restValue})`;
1852
1867
  case "utcDateTime":
1853
1868
  return `${nullOrUndefinedPrefix} new Date(${type.encode === "unixTimestamp" ? `${restValue} * 1000` : restValue})`;
1854
1869
  case "array": {
@@ -2088,3 +2103,32 @@ export function getExpectedStatuses(operation: ServiceOperation): string {
2088
2103
 
2089
2104
  return `[${statusCodes.map((x) => `"${x}"`).join(", ")}]`;
2090
2105
  }
2106
+
2107
+ /**
2108
+ * Gets the apiVersion expression with default value fallback for query parameters.
2109
+ * @param dpgContext - The SDK context
2110
+ * @param operation - The operation to get the apiVersion parameter from
2111
+ * @returns The apiVersion expression string, or undefined if no apiVersion query param exists
2112
+ */
2113
+ function getApiVersionExpression(
2114
+ dpgContext: SdkContext,
2115
+ operation: ServiceOperation
2116
+ ): string | undefined {
2117
+ const queryApiVersionParam = operation.operation.parameters.find(
2118
+ (p) => p.kind === "query" && p.isApiVersionParam
2119
+ );
2120
+ if (!queryApiVersionParam) {
2121
+ return undefined;
2122
+ }
2123
+ // For multi-service, use only the default value (don't reference context.apiVersion)
2124
+ if (dpgContext.rlcOptions?.isMultiService) {
2125
+ return queryApiVersionParam.clientDefaultValue
2126
+ ? `"${queryApiVersionParam.clientDefaultValue}"`
2127
+ : undefined;
2128
+ }
2129
+ const paramAccess = `${queryApiVersionParam.onClient ? "context." : ""}${queryApiVersionParam.name}`;
2130
+ const defaultValueSuffix = queryApiVersionParam.clientDefaultValue
2131
+ ? ` ?? "${queryApiVersionParam.clientDefaultValue}"`
2132
+ : "";
2133
+ return `${paramAccess}${defaultValueSuffix}`;
2134
+ }
@@ -78,7 +78,7 @@ const NumericTypeKinds = [
78
78
  "decimal128"
79
79
  ];
80
80
 
81
- const DateTimeTypeKinds = ["plainDate", "plainTime"];
81
+ const DateTimeTypeKinds = ["plainTime"];
82
82
 
83
83
  // This may be a good candidate to move to TCGC
84
84
  export function isNumericTypeKind(kind: string): boolean {
@@ -178,7 +178,11 @@ function buildPolymorphicDeserializer(
178
178
 
179
179
  const subTypes = type.discriminatedSubtypes;
180
180
  if (!subTypes) {
181
- return;
181
+ // No subtypes - treat as a regular model and generate simple deserializer
182
+ return buildModelTypeDeserializer(context, type, {
183
+ nameOnly,
184
+ skipDiscriminatedUnionSuffix: false
185
+ });
182
186
  }
183
187
 
184
188
  const cases: string[] = [];
@@ -184,7 +184,11 @@ function buildPolymorphicSerializer(
184
184
 
185
185
  const subTypes = type.discriminatedSubtypes;
186
186
  if (!subTypes) {
187
- return;
187
+ // No subtypes - treat as a regular model and generate simple serializer
188
+ return buildModelTypeSerializer(context, type, {
189
+ nameOnly,
190
+ skipDiscriminatedUnionSuffix: false
191
+ });
188
192
  }
189
193
 
190
194
  const cases: string[] = [];
@@ -81,6 +81,7 @@ export function isSpecialUnionVariant(
81
81
 
82
82
  if (
83
83
  t.kind === "utcDateTime" ||
84
+ t.kind === "plainDate" ||
84
85
  t.kind === "bytes" ||
85
86
  (t.kind === "model" &&
86
87
  t.properties
@@ -62,7 +62,6 @@ export function getTypeExpression(
62
62
  }
63
63
  return "number";
64
64
  case "endpoint":
65
- case "plainDate":
66
65
  case "plainTime":
67
66
  case "string":
68
67
  case "url":
@@ -103,6 +102,7 @@ export function getTypeExpression(
103
102
  case "union":
104
103
  return getUnionExpression(context, type, options);
105
104
  case "utcDateTime":
105
+ case "plainDate":
106
106
  return "Date";
107
107
 
108
108
  default:
@@ -58,7 +58,7 @@ export async function transformRLCModel(
58
58
  ? client.name
59
59
  : (options?.title ??
60
60
  client.name ??
61
- getDefaultService(program)?.title ??
61
+ getDefaultService(program, options.isModularLibrary)?.title ??
62
62
  ""),
63
63
  NameType.Class
64
64
  );
@@ -123,7 +123,10 @@ export function transformUrlInfo(
123
123
  const importedModels = new Set<string>();
124
124
  const usage = [SchemaContext.Exception, SchemaContext.Input];
125
125
  const program = dpgContext.program;
126
- const serviceNs = getDefaultService(program)?.type;
126
+ const serviceNs = getDefaultService(
127
+ program,
128
+ dpgContext.rlcOptions?.isModularLibrary
129
+ )?.type;
127
130
  let endpoint = undefined;
128
131
  const urlParameters: PathParameter[] = [];
129
132
  if (serviceNs) {
@@ -96,7 +96,7 @@ function transformOperation(
96
96
  responseTypes,
97
97
  operationGroupName
98
98
  ),
99
- isPaging: isPagingOperation(program, route)
99
+ isPaging: isPagingOperation(dpgContext, route)
100
100
  }
101
101
  };
102
102
  if (