@azure-tools/typespec-ts 0.48.0 → 0.48.1-alpha.20260127.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 (60) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +20 -5
  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 +7 -3
  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 +24 -3
  10. package/dist/src/modular/buildOperations.js.map +1 -1
  11. package/dist/src/modular/emitModels.d.ts.map +1 -1
  12. package/dist/src/modular/emitModels.js +19 -0
  13. package/dist/src/modular/emitModels.js.map +1 -1
  14. package/dist/src/modular/emitSamples.js +2 -2
  15. package/dist/src/modular/emitSamples.js.map +1 -1
  16. package/dist/src/modular/helpers/clientHelpers.d.ts +2 -1
  17. package/dist/src/modular/helpers/clientHelpers.d.ts.map +1 -1
  18. package/dist/src/modular/helpers/clientHelpers.js +5 -2
  19. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  20. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  21. package/dist/src/modular/helpers/operationHelpers.js +266 -43
  22. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  23. package/dist/src/modular/serialization/buildXmlSerializerFunction.d.ts +32 -0
  24. package/dist/src/modular/serialization/buildXmlSerializerFunction.d.ts.map +1 -0
  25. package/dist/src/modular/serialization/buildXmlSerializerFunction.js +373 -0
  26. package/dist/src/modular/serialization/buildXmlSerializerFunction.js.map +1 -0
  27. package/dist/src/modular/static-helpers-metadata.d.ts +57 -0
  28. package/dist/src/modular/static-helpers-metadata.d.ts.map +1 -1
  29. package/dist/src/modular/static-helpers-metadata.js +57 -0
  30. package/dist/src/modular/static-helpers-metadata.js.map +1 -1
  31. package/dist/src/utils/clientUtils.d.ts.map +1 -1
  32. package/dist/src/utils/clientUtils.js +1 -0
  33. package/dist/src/utils/clientUtils.js.map +1 -1
  34. package/dist/src/utils/mediaTypes.d.ts +4 -0
  35. package/dist/src/utils/mediaTypes.d.ts.map +1 -1
  36. package/dist/src/utils/mediaTypes.js +10 -0
  37. package/dist/src/utils/mediaTypes.js.map +1 -1
  38. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  39. package/dist/src/utils/modelUtils.js +3 -0
  40. package/dist/src/utils/modelUtils.js.map +1 -1
  41. package/dist/src/utils/operationUtil.d.ts +12 -0
  42. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  43. package/dist/src/utils/operationUtil.js +22 -1
  44. package/dist/src/utils/operationUtil.js.map +1 -1
  45. package/dist/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +8 -7
  47. package/src/index.ts +20 -5
  48. package/src/modular/buildClientContext.ts +12 -5
  49. package/src/modular/buildOperations.ts +34 -3
  50. package/src/modular/emitModels.ts +43 -0
  51. package/src/modular/emitSamples.ts +2 -2
  52. package/src/modular/helpers/clientHelpers.ts +6 -2
  53. package/src/modular/helpers/operationHelpers.ts +377 -57
  54. package/src/modular/serialization/buildXmlSerializerFunction.ts +511 -0
  55. package/src/modular/static-helpers-metadata.ts +58 -0
  56. package/src/utils/clientUtils.ts +1 -0
  57. package/src/utils/mediaTypes.ts +12 -0
  58. package/src/utils/modelUtils.ts +3 -0
  59. package/src/utils/operationUtil.ts +34 -1
  60. package/static/static-helpers/serialization/xml-helpers.ts +596 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.48.0",
3
+ "version": "0.48.1-alpha.20260127.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.35-dev.9",
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,8 @@
73
73
  "@typespec/xml": "^0.78.0"
74
74
  },
75
75
  "dependencies": {
76
- "@azure-tools/rlc-common": "^0.48.0",
76
+ "@azure-tools/rlc-common": "0.48.1-alpha.20260127.1",
77
+ "fast-xml-parser": "^4.5.0",
77
78
  "fs-extra": "^11.1.0",
78
79
  "lodash": "^4.17.21",
79
80
  "prettier": "^3.3.3",
package/src/index.ts CHANGED
@@ -18,7 +18,8 @@ import {
18
18
  PollingHelpers,
19
19
  SerializationHelpers,
20
20
  SimplePollerHelpers,
21
- UrlTemplateHelpers
21
+ UrlTemplateHelpers,
22
+ XmlHelpers
22
23
  } from "./modular/static-helpers-metadata.js";
23
24
  import {
24
25
  RLCModel,
@@ -92,6 +93,7 @@ import { getModuleExports } from "./modular/buildProjectFiles.js";
92
93
  import { getClientHierarchyMap, getRLCClients } from "./utils/clientUtils.js";
93
94
  import { join } from "path";
94
95
  import { loadStaticHelpers } from "./framework/load-static-helpers.js";
96
+ import { packageUsesXmlSerialization } from "./modular/serialization/buildXmlSerializerFunction.js";
95
97
  import { provideBinder } from "./framework/hooks/binder.js";
96
98
  import { provideSdkTypes } from "./framework/hooks/sdkTypes.js";
97
99
  import { transformRLCModel } from "./transform/transform.js";
@@ -135,7 +137,8 @@ export async function $onEmit(context: EmitContext) {
135
137
  ...SimplePollerHelpers,
136
138
  ...UrlTemplateHelpers,
137
139
  ...MultipartHelpers,
138
- ...CloudSettingHelpers
140
+ ...CloudSettingHelpers,
141
+ ...XmlHelpers
139
142
  },
140
143
  {
141
144
  sourcesDir: dpgContext.generationPathDetail?.modularSourcesDir,
@@ -479,17 +482,29 @@ export async function $onEmit(context: EmitContext) {
479
482
  modularPackageInfo = {
480
483
  exports: getModuleExports(context, modularEmitterOptions)
481
484
  };
485
+ // Build dependencies
486
+ const dependencies: Record<string, string> = {};
487
+ if (isAzureFlavor) {
488
+ dependencies["@azure/core-util"] = "^1.9.2";
489
+ }
490
+ // Add fast-xml-parser if XML serialization is used
491
+ if (packageUsesXmlSerialization(dpgContext.sdkPackage)) {
492
+ dependencies["fast-xml-parser"] = "^4.5.0";
493
+ }
482
494
  if (isAzureFlavor) {
483
495
  modularPackageInfo = {
484
496
  ...modularPackageInfo,
485
- dependencies: {
486
- "@azure/core-util": "^1.9.2"
487
- },
497
+ dependencies,
488
498
  clientContextPaths: getRelativeContextPaths(
489
499
  context,
490
500
  modularEmitterOptions
491
501
  )
492
502
  };
503
+ } else if (Object.keys(dependencies).length > 0) {
504
+ modularPackageInfo = {
505
+ ...modularPackageInfo,
506
+ dependencies
507
+ };
493
508
  }
494
509
  }
495
510
  commonBuilders.push((model) =>
@@ -200,10 +200,20 @@ export function buildClientContext(
200
200
  const { endpointParamName: endpointParam, assignedOptionalParams } =
201
201
  buildGetClientEndpointParam(factoryFunction, dpgContext, client);
202
202
  const credentialParam = buildGetClientCredentialParam(client, emitterOptions);
203
+
204
+ // Get api version param early so we can use its name when building options
205
+ const apiVersionParam = getClientParameters(client, dpgContext).find(
206
+ (x) => x.isApiVersionParam
207
+ );
208
+ const apiVersionParamName = apiVersionParam
209
+ ? getClientParameterName(apiVersionParam)
210
+ : undefined;
211
+
203
212
  const optionsParam = buildGetClientOptionsParam(
204
213
  factoryFunction,
205
214
  emitterOptions,
206
- endpointParam
215
+ endpointParam,
216
+ apiVersionParamName
207
217
  );
208
218
 
209
219
  factoryFunction.addStatements(
@@ -230,9 +240,6 @@ export function buildClientContext(
230
240
  }
231
241
 
232
242
  let apiVersionPolicyStatement = `clientContext.pipeline.removePolicy({ name: "ApiVersionPolicy" });`;
233
- const apiVersionParam = getClientParameters(client, dpgContext).find(
234
- (x) => x.isApiVersionParam
235
- );
236
243
  const endpointParameter = getClientParameters(client, dpgContext, {
237
244
  onClientOnly: false,
238
245
  requiredOnly: true,
@@ -248,7 +255,7 @@ export function buildClientContext(
248
255
  const apiVersionInEndpoint =
249
256
  templateArguments && templateArguments.find((p) => p.isApiVersionParam);
250
257
  if (!apiVersionInEndpoint && apiVersionParam.clientDefaultValue) {
251
- apiVersionPolicyStatement += `const apiVersion = options.apiVersion ?? "${apiVersionParam.clientDefaultValue}";`;
258
+ apiVersionPolicyStatement += `const ${apiVersionParamName} = options.${apiVersionParamName} ?? "${apiVersionParam.clientDefaultValue}";`;
252
259
  }
253
260
 
254
261
  if (apiVersionParam.kind === "method") {
@@ -11,7 +11,8 @@ import {
11
11
  getOperationFunction,
12
12
  getOperationOptionsName,
13
13
  getSendPrivateFunction,
14
- isLroOnlyOperation
14
+ isLroOnlyOperation,
15
+ isLroAndPagingOperation
15
16
  } from "./helpers/operationHelpers.js";
16
17
 
17
18
  import { OperationPathAndDeserDetails } from "./interfaces.js";
@@ -30,7 +31,8 @@ import {
30
31
  } from "@azure-tools/typespec-client-generator-core";
31
32
  import {
32
33
  getMethodHierarchiesMap,
33
- ServiceOperation
34
+ ServiceOperation,
35
+ hasDualFormatSupport
34
36
  } from "../utils/operationUtil.js";
35
37
  import { resolveReference } from "../framework/reference.js";
36
38
  import { useDependencies } from "../framework/hooks/useDependencies.js";
@@ -144,6 +146,20 @@ export function buildOperationOptions(
144
146
  docs: ["Delay to wait until next poll, in milliseconds."]
145
147
  };
146
148
 
149
+ // Check if this operation supports both JSON and XML content types
150
+ const bodyContentTypes = operation.operation.bodyParam?.contentTypes ?? [];
151
+ const isDualFormat = hasDualFormatSupport(bodyContentTypes);
152
+
153
+ // Content type option for dual-format operations
154
+ const contentTypeOption = {
155
+ name: "contentType",
156
+ type: "string",
157
+ hasQuestionToken: true,
158
+ docs: [
159
+ 'The content type for the request body. Defaults to "application/json". Use "application/xml" for XML serialization.'
160
+ ]
161
+ };
162
+
147
163
  // handle optional body parameter
148
164
  // if (operation.operation.bodyParam?.optional === true) {
149
165
  // options.push(operation.operation.bodyParam);
@@ -151,12 +167,27 @@ export function buildOperationOptions(
151
167
  const operationOptionsReference = resolveReference(
152
168
  dependencies.OperationOptions
153
169
  );
170
+
171
+ // Build the additional options array
172
+ const additionalOptions: {
173
+ name: string;
174
+ type: string;
175
+ hasQuestionToken: boolean;
176
+ docs: string[];
177
+ }[] = [];
178
+ if (isLroOnlyOperation(operation) || isLroAndPagingOperation(operation)) {
179
+ additionalOptions.push(lroOptions);
180
+ }
181
+ if (isDualFormat) {
182
+ additionalOptions.push(contentTypeOption);
183
+ }
184
+
154
185
  const operationOptionsInterface: InterfaceDeclarationStructure = {
155
186
  kind: StructureKind.Interface,
156
187
  name,
157
188
  isExported: true,
158
189
  extends: [operationOptionsReference],
159
- properties: (isLroOnlyOperation(operation) ? [lroOptions] : []).concat(
190
+ properties: additionalOptions.concat(
160
191
  options.map((p) => {
161
192
  return {
162
193
  docs: getDocsFromDescription(p.doc),
@@ -48,6 +48,11 @@ import {
48
48
  buildModelSerializer,
49
49
  buildPropertySerializer
50
50
  } from "./serialization/buildSerializerFunction.js";
51
+ import {
52
+ buildXmlModelSerializer,
53
+ buildXmlModelDeserializer,
54
+ hasXmlSerialization
55
+ } from "./serialization/buildXmlSerializerFunction.js";
51
56
  import path from "path";
52
57
  import { refkey } from "../framework/refkey.js";
53
58
  import { useContext } from "../contextManager.js";
@@ -334,6 +339,8 @@ function addSerializationFunctions(
334
339
  nameOnly: false,
335
340
  skipDiscriminatedUnionSuffix
336
341
  };
342
+
343
+ // Add JSON serializers
337
344
  const serializationFunction =
338
345
  typeOrProperty.kind === "property"
339
346
  ? buildPropertySerializer(context, typeOrProperty, options)
@@ -359,6 +366,42 @@ function addSerializationFunctions(
359
366
  ) {
360
367
  addDeclaration(sourceFile, deserializationFunction, deserializerRefKey);
361
368
  }
369
+
370
+ // Add XML serializers if the type has XML serialization options
371
+ if (typeOrProperty.kind === "model" && hasXmlSerialization(typeOrProperty)) {
372
+ const xmlSerializerRefKey = refkey(typeOrProperty, "xmlSerializer");
373
+ const xmlDeserializerRefKey = refkey(typeOrProperty, "xmlDeserializer");
374
+
375
+ const xmlSerializationFunction = buildXmlModelSerializer(
376
+ context,
377
+ typeOrProperty,
378
+ options
379
+ );
380
+ if (
381
+ xmlSerializationFunction &&
382
+ typeof xmlSerializationFunction !== "string" &&
383
+ xmlSerializationFunction.name
384
+ ) {
385
+ addDeclaration(sourceFile, xmlSerializationFunction, xmlSerializerRefKey);
386
+ }
387
+
388
+ const xmlDeserializationFunction = buildXmlModelDeserializer(
389
+ context,
390
+ typeOrProperty,
391
+ options
392
+ );
393
+ if (
394
+ xmlDeserializationFunction &&
395
+ typeof xmlDeserializationFunction !== "string" &&
396
+ xmlDeserializationFunction.name
397
+ ) {
398
+ addDeclaration(
399
+ sourceFile,
400
+ xmlDeserializationFunction,
401
+ xmlDeserializerRefKey
402
+ );
403
+ }
404
+ }
362
405
  }
363
406
 
364
407
  function buildUnionType(
@@ -281,7 +281,7 @@ function prepareExampleValue(
281
281
  onClient?: boolean
282
282
  ): ExampleValue {
283
283
  return {
284
- name: normalizeName(name, NameType.Parameter),
284
+ name: normalizeName(name, NameType.Parameter, true),
285
285
  value:
286
286
  typeof value === "string" ? value : getParameterValue(context, value),
287
287
  isOptional: Boolean(isOptional),
@@ -411,7 +411,7 @@ function prepareExampleParameters(
411
411
  const bodyParam = method.operation.bodyParam;
412
412
  const bodySerializeName = bodyParam?.serializedName;
413
413
  const bodyExample = parameterMap[bodySerializeName ?? ""];
414
- if (bodySerializeName && bodyExample && bodyExample.value) {
414
+ if (bodyParam && bodyExample && bodyExample.value) {
415
415
  if (
416
416
  isSpreadBodyParameter(bodyParam) &&
417
417
  bodyParam.type.kind === "model" &&
@@ -249,12 +249,14 @@ export function buildGetClientEndpointParam(
249
249
  *
250
250
  * @param context - context in which the options are being passed; statements will be added to this context
251
251
  * to help build the options shape
252
+ * @param apiVersionParamName - the name of the api version parameter in options (e.g., "apiVersion" or "version")
252
253
  * @returns - an expression representing the options to be passed in to getClient
253
254
  */
254
255
  export function buildGetClientOptionsParam(
255
256
  context: StatementedNode,
256
257
  emitterOptions: ModularEmitterOptions,
257
- endpointParam: string
258
+ endpointParam: string,
259
+ apiVersionParamName?: string
258
260
  ): string {
259
261
  const userAgentOptions = buildUserAgentOptions(
260
262
  context,
@@ -264,7 +266,9 @@ export function buildGetClientOptionsParam(
264
266
  const loggingOptions = buildLoggingOptions(emitterOptions.options.flavor);
265
267
  const credentials = buildCredentials(emitterOptions, endpointParam);
266
268
 
267
- let expr = "const { apiVersion: _, ...updatedOptions } = {";
269
+ // Use the actual api version parameter name for destructuring, defaulting to "apiVersion"
270
+ const apiVersionDestructure = apiVersionParamName ?? "apiVersion";
271
+ let expr = `const { ${apiVersionDestructure}: _, ...updatedOptions } = {`;
268
272
 
269
273
  expr += "...options,";
270
274