@azure-tools/typespec-ts 0.34.0 → 0.35.0-alpha.20241203.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 (70) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +16 -0
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/index.js +22 -19
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/lib.d.ts +19 -1
  7. package/dist/src/lib.d.ts.map +1 -1
  8. package/dist/src/lib.js +14 -1
  9. package/dist/src/lib.js.map +1 -1
  10. package/dist/src/modular/buildClassicalClient.js +2 -2
  11. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  12. package/dist/src/modular/buildCodeModel.d.ts.map +1 -1
  13. package/dist/src/modular/buildCodeModel.js +18 -0
  14. package/dist/src/modular/buildCodeModel.js.map +1 -1
  15. package/dist/src/modular/helpers/clientHelpers.js +1 -1
  16. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  17. package/dist/src/modular/helpers/operationHelpers.js +2 -2
  18. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  19. package/dist/src/transform/transform.d.ts.map +1 -1
  20. package/dist/src/transform/transform.js +7 -5
  21. package/dist/src/transform/transform.js.map +1 -1
  22. package/dist/src/transform/transformApiVersionInfo.js +2 -2
  23. package/dist/src/transform/transformApiVersionInfo.js.map +1 -1
  24. package/dist/src/transform/transformHelperFunctionDetails.js +2 -29
  25. package/dist/src/transform/transformHelperFunctionDetails.js.map +1 -1
  26. package/dist/src/transform/transformParameters.d.ts +8 -1
  27. package/dist/src/transform/transformParameters.d.ts.map +1 -1
  28. package/dist/src/transform/transformParameters.js +63 -38
  29. package/dist/src/transform/transformParameters.js.map +1 -1
  30. package/dist/src/transform/transformPaths.d.ts.map +1 -1
  31. package/dist/src/transform/transformPaths.js +14 -6
  32. package/dist/src/transform/transformPaths.js.map +1 -1
  33. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  34. package/dist/src/transform/transfromRLCOptions.js +6 -4
  35. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  36. package/dist/src/utils/emitUtil.js +3 -0
  37. package/dist/src/utils/emitUtil.js.map +1 -1
  38. package/dist/src/utils/modelUtils.d.ts +2 -1
  39. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  40. package/dist/src/utils/modelUtils.js +10 -25
  41. package/dist/src/utils/modelUtils.js.map +1 -1
  42. package/dist/src/utils/operationUtil.d.ts +1 -4
  43. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  44. package/dist/src/utils/operationUtil.js +8 -22
  45. package/dist/src/utils/operationUtil.js.map +1 -1
  46. package/dist/src/utils/parameterUtils.d.ts +9 -0
  47. package/dist/src/utils/parameterUtils.d.ts.map +1 -0
  48. package/dist/src/utils/parameterUtils.js +165 -0
  49. package/dist/src/utils/parameterUtils.js.map +1 -0
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +20 -20
  52. package/src/index.ts +22 -24
  53. package/src/lib.ts +14 -1
  54. package/src/modular/buildClassicalClient.ts +2 -2
  55. package/src/modular/buildCodeModel.ts +19 -1
  56. package/src/modular/helpers/clientHelpers.ts +1 -1
  57. package/src/modular/helpers/operationHelpers.ts +2 -2
  58. package/src/transform/transform.ts +3 -1
  59. package/src/transform/transformApiVersionInfo.ts +2 -2
  60. package/src/transform/transformHelperFunctionDetails.ts +2 -27
  61. package/src/transform/transformParameters.ts +83 -42
  62. package/src/transform/transformPaths.ts +23 -5
  63. package/src/transform/transfromRLCOptions.ts +6 -4
  64. package/src/utils/emitUtil.ts +3 -0
  65. package/src/utils/modelUtils.ts +14 -34
  66. package/src/utils/operationUtil.ts +14 -23
  67. package/src/utils/parameterUtils.ts +234 -0
  68. package/static/static-helpers/pagingHelpers.ts +0 -3
  69. package/static/static-helpers/pollingHelpers.ts +0 -3
  70. package/static/static-helpers/serialization/build-csv-collection.ts +0 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.34.0",
3
+ "version": "0.35.0-alpha.20241203.1",
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
- "@azure-tools/cadl-ranch-expect": "^0.15.5",
22
- "@azure-tools/cadl-ranch-specs": "^0.38.0",
23
- "@azure-tools/cadl-ranch": "^0.15.0",
21
+ "@azure-tools/cadl-ranch-expect": "^0.15.6",
22
+ "@azure-tools/cadl-ranch-specs": "^0.39.2",
23
+ "@azure-tools/cadl-ranch": "^0.16.1",
24
24
  "@azure-tools/cadl-ranch-api": "^0.5.0",
25
- "@azure-tools/typespec-autorest": ">=0.47.0 <1.0.0",
26
- "@azure-tools/typespec-azure-core": ">=0.47.0 <1.0.0",
27
- "@azure-tools/typespec-azure-resource-manager": ">=0.47.0 <1.0.0",
28
- "@azure-tools/typespec-client-generator-core": ">=0.47.4 <1.0.0",
25
+ "@azure-tools/typespec-autorest": ">=0.48.0 <1.0.0",
26
+ "@azure-tools/typespec-azure-core": ">=0.48.0 <1.0.0",
27
+ "@azure-tools/typespec-azure-resource-manager": ">=0.48.0 <1.0.0",
28
+ "@azure-tools/typespec-client-generator-core": ">=0.48.0 <1.0.0",
29
29
  "@azure/abort-controller": "^2.1.2",
30
30
  "@azure/core-auth": "^1.6.0",
31
31
  "@azure/core-lro": "^3.1.0",
@@ -40,12 +40,12 @@
40
40
  "@types/node": "^18.0.0",
41
41
  "@typescript-eslint/eslint-plugin": "^6.8.0",
42
42
  "@typescript-eslint/parser": "^6.8.0",
43
- "@typespec/compiler": ">=0.61.2 <1.0.0",
44
- "@typespec/http": ">=0.61.0 <1.0.0",
45
- "@typespec/openapi": ">=0.61.0, <1.0.0",
46
- "@typespec/rest": ">=0.61.0 <1.0.0",
43
+ "@typespec/compiler": ">=0.62.0 <1.0.0",
44
+ "@typespec/http": ">=0.62.0 <1.0.0",
45
+ "@typespec/openapi": ">=0.62.0, <1.0.0",
46
+ "@typespec/rest": ">=0.62.0 <1.0.0",
47
47
  "@typespec/ts-http-runtime": "1.0.0-alpha.20240314.2",
48
- "@typespec/versioning": ">=0.61.0 <1.0.0",
48
+ "@typespec/versioning": ">=0.62.0 <1.0.0",
49
49
  "chai": "^4.3.6",
50
50
  "chalk": "^4.0.0",
51
51
  "cross-env": "^7.0.3",
@@ -65,15 +65,15 @@
65
65
  "tsx": "^4.16.5"
66
66
  },
67
67
  "peerDependencies": {
68
- "@azure-tools/typespec-azure-core": ">=0.47.0 <1.0.0",
69
- "@azure-tools/typespec-client-generator-core": ">=0.47.4 <1.0.0",
70
- "@typespec/compiler": ">=0.61.2 <1.0.0",
71
- "@typespec/http": ">=0.61.0 <1.0.0",
72
- "@typespec/rest": ">=0.61.0 <1.0.0",
73
- "@typespec/versioning": ">=0.61.0 <1.0.0"
68
+ "@azure-tools/typespec-azure-core": ">=0.48.0 <1.0.0",
69
+ "@azure-tools/typespec-client-generator-core": ">=0.48.0 <1.0.0",
70
+ "@typespec/compiler": ">=0.62.0 <1.0.0",
71
+ "@typespec/http": ">=0.62.0 <1.0.0",
72
+ "@typespec/rest": ">=0.62.0 <1.0.0",
73
+ "@typespec/versioning": ">=0.62.0 <1.0.0"
74
74
  },
75
75
  "dependencies": {
76
- "@azure-tools/rlc-common": "^0.34.0",
76
+ "@azure-tools/rlc-common": "^0.35.0",
77
77
  "fs-extra": "^11.1.0",
78
78
  "lodash": "^4.17.21",
79
79
  "prettier": "^3.3.3",
package/src/index.ts CHANGED
@@ -91,10 +91,9 @@ export async function $onEmit(context: EmitContext) {
91
91
  const program: Program = context.program;
92
92
  const emitterOptions: EmitterOptions = context.options;
93
93
  const dpgContext = await createContextWithDefaultOptions(context);
94
- const rlcOptions: RLCOptions = transformRLCOptions(
95
- emitterOptions,
96
- dpgContext
97
- );
94
+ // Enrich the dpg context with path detail and common options
95
+ await enrichDpgContext();
96
+ const rlcOptions = dpgContext.rlcOptions ?? {};
98
97
 
99
98
  const needUnexpectedHelper: Map<string, boolean> = new Map<string, boolean>();
100
99
  const serviceNameToRlcModelsMap: Map<string, RLCModel> = new Map<
@@ -109,7 +108,6 @@ export async function $onEmit(context: EmitContext) {
109
108
  compilerContext: context,
110
109
  tcgcContext: dpgContext
111
110
  });
112
- const { modularSourcesDir } = await calculateGenerationDir(rlcOptions);
113
111
  const staticHelpers = await loadStaticHelpers(
114
112
  outputProject,
115
113
  {
@@ -117,7 +115,7 @@ export async function $onEmit(context: EmitContext) {
117
115
  ...PagingHelpers,
118
116
  ...PollingHelpers
119
117
  },
120
- { sourcesDir: modularSourcesDir }
118
+ { sourcesDir: dpgContext.generationPathDetail?.modularSourcesDir }
121
119
  );
122
120
  const extraDependencies = isAzurePackage({ options: rlcOptions })
123
121
  ? {
@@ -136,11 +134,10 @@ export async function $onEmit(context: EmitContext) {
136
134
 
137
135
  const rlcCodeModels: RLCModel[] = [];
138
136
  let modularCodeModel: ModularCodeModel;
139
- // 1. Enrich the dpg context with path detail and common options
140
- await enrichDpgContext();
141
- // 2. Clear sources folder
137
+
138
+ // 1. Clear sources folder
142
139
  await clearSrcFolder();
143
- // 3. Generate RLC code model
140
+ // 2. Generate RLC code model
144
141
  // TODO: skip this step in modular once modular generator is sufficiently decoupled
145
142
  await buildRLCCodeModels();
146
143
 
@@ -155,28 +152,26 @@ export async function $onEmit(context: EmitContext) {
155
152
  await generateMetadataAndTest();
156
153
 
157
154
  async function enrichDpgContext() {
158
- const options: RLCOptions = transformRLCOptions(emitterOptions, dpgContext);
159
155
  const generationPathDetail: GenerationDirDetail =
160
- await calculateGenerationDir(options);
156
+ await calculateGenerationDir();
161
157
  dpgContext.generationPathDetail = generationPathDetail;
158
+ const options: RLCOptions = transformRLCOptions(emitterOptions, dpgContext);
159
+ // clear output folder if needed
160
+ if (options.clearOutputFolder) {
161
+ await fsextra.emptyDir(context.emitterOutputDir);
162
+ }
162
163
  const hasTestFolder = await fsextra.pathExists(
163
164
  join(dpgContext.generationPathDetail?.metadataDir ?? "", "test")
164
165
  );
165
- rlcOptions.generateTest =
166
- rlcOptions.generateTest === true ||
167
- (rlcOptions.generateTest === undefined &&
166
+ options.generateTest =
167
+ options.generateTest === true ||
168
+ (options.generateTest === undefined &&
168
169
  !hasTestFolder &&
169
- isAzurePackage({ options: rlcOptions }));
170
- dpgContext.rlcOptions = rlcOptions;
170
+ isAzurePackage({ options: options }));
171
+ dpgContext.rlcOptions = options;
171
172
  }
172
173
 
173
- async function calculateGenerationDir(
174
- options: RLCOptions
175
- ): Promise<GenerationDirDetail> {
176
- // clear output folder if needed
177
- if (options.clearOutputFolder) {
178
- await fsextra.emptyDir(context.emitterOutputDir);
179
- }
174
+ async function calculateGenerationDir(): Promise<GenerationDirDetail> {
180
175
  const projectRoot = context.emitterOutputDir ?? "";
181
176
  const customizationFolder = join(projectRoot, "generated");
182
177
  // if customization folder exists, use it as sources root
@@ -304,6 +299,9 @@ export async function $onEmit(context: EmitContext) {
304
299
  }
305
300
 
306
301
  binder.resolveAllReferences(modularSourcesRoot);
302
+ if (program.compilerOptions.noEmit || program.hasError()) {
303
+ return;
304
+ }
307
305
 
308
306
  for (const file of project.getSourceFiles()) {
309
307
  file.fixMissingImports(
package/src/lib.ts CHANGED
@@ -92,7 +92,8 @@ export const RLCOptionsSchema: JSONSchemaType<EmitterOptions> = {
92
92
  compatibilityMode: { type: "boolean", nullable: true },
93
93
  experimentalExtensibleEnums: { type: "boolean", nullable: true },
94
94
  clearOutputFolder: { type: "boolean", nullable: true },
95
- ignorePropertyNameNormalize: { type: "boolean", nullable: true }
95
+ ignorePropertyNameNormalize: { type: "boolean", nullable: true },
96
+ compatibilityQueryMultiFormat: { type: "boolean", nullable: true }
96
97
  },
97
98
  required: []
98
99
  };
@@ -267,6 +268,18 @@ const libDef = {
267
268
  messages: {
268
269
  default: paramMessage`Path parameter '${"paramName"}' cannot be optional.`
269
270
  }
271
+ },
272
+ "un-supported-format-cases": {
273
+ severity: "warning",
274
+ messages: {
275
+ default: paramMessage`The parameter ${"paramName"} with explode: ${"explode"} and format: ${"format"} is not supported.`
276
+ }
277
+ },
278
+ "parameter-type-not-supported": {
279
+ severity: "warning",
280
+ messages: {
281
+ default: paramMessage`Parameter '${"paramName"}' with type '${"paramType"}' is not supported and we would ignore this parameter.`
282
+ }
270
283
  }
271
284
  },
272
285
  emitter: {
@@ -108,9 +108,9 @@ export function buildClassicalClient(
108
108
  });
109
109
 
110
110
  constructor.addStatements([
111
- `this._client = create${modularClientName}(${paramNames.join(",")})`
111
+ `this._client = create${modularClientName}(${paramNames.join(",")});`
112
112
  ]);
113
- constructor.addStatements(`this.pipeline = this._client.pipeline`);
113
+ constructor.addStatements(`this.pipeline = this._client.pipeline;`);
114
114
 
115
115
  buildClientOperationGroups(clientFile, _client, dpgContext, clientClass);
116
116
  importAllApis(clientFile, srcPath, subfolder);
@@ -509,7 +509,19 @@ function emitParameter(
509
509
  context: SdkContext,
510
510
  parameter: HttpOperationParameter | HttpServerParameter,
511
511
  implementation: string
512
- ): Parameter {
512
+ ): Parameter | undefined {
513
+ if (parameter.type === "cookie") {
514
+ // TODO: support cookie parameters, https://github.com/Azure/autorest.typescript/issues/2898
515
+ reportDiagnostic(context.program, {
516
+ code: "parameter-type-not-supported",
517
+ format: {
518
+ paramType: parameter.type,
519
+ paramName: parameter.name
520
+ },
521
+ target: NoTarget
522
+ });
523
+ return undefined;
524
+ }
513
525
  const base = emitParamBase(context, parameter.param);
514
526
  let type = getType(context, parameter.param.type, {
515
527
  usage: UsageFlags.Input
@@ -857,6 +869,9 @@ function emitBasicOperation(
857
869
  continue;
858
870
  }
859
871
  const emittedParam = emitParameter(context, param, "Method");
872
+ if (emittedParam === undefined) {
873
+ continue;
874
+ }
860
875
  if (isApiVersion(context, param)) {
861
876
  emittedParam.isApiVersion = true;
862
877
  methodApiVersionParam = emittedParam;
@@ -1719,6 +1734,9 @@ function emitServerParams(
1719
1734
  serverParameter,
1720
1735
  "Client"
1721
1736
  );
1737
+ if (emittedParameter === undefined) {
1738
+ continue;
1739
+ }
1722
1740
  endpointPathParameters.push(emittedParameter);
1723
1741
  if (isApiVersion(context, serverParameter as any)) {
1724
1742
  emittedParameter.isApiVersion = true;
@@ -228,7 +228,7 @@ export function buildGetClientOptionsParam(
228
228
  expr += `credentials: ${credentials},`;
229
229
  }
230
230
 
231
- expr += `}`;
231
+ expr += `};`;
232
232
 
233
233
  context.addStatements(expr);
234
234
  return "updatedOptions";
@@ -997,7 +997,7 @@ export function serializeRequestValue(
997
997
  case "headerDefault":
998
998
  return `${nullOrUndefinedPrefix}${clientValue}.toUTCString()`;
999
999
  case "unixTimestamp":
1000
- return `${nullOrUndefinedPrefix}${clientValue}.getTime()`;
1000
+ return `${nullOrUndefinedPrefix}((${clientValue}.getTime() / 1000) | 0)`;
1001
1001
  case "rfc3339":
1002
1002
  default:
1003
1003
  return `${getNullableCheck(clientValue, type)} ${clientValue}${
@@ -1086,7 +1086,7 @@ export function deserializeResponseValue(
1086
1086
  : "";
1087
1087
  switch (type.type) {
1088
1088
  case "datetime":
1089
- return `${nullOrUndefinedPrefix} new Date(${restValue})`;
1089
+ return `${nullOrUndefinedPrefix} new Date(${type.format === "unixTimestamp" ? `${restValue} * 1000` : restValue})`;
1090
1090
  case "list": {
1091
1091
  const prefix = nullOrUndefinedPrefix + restValue;
1092
1092
  let elementNullOrUndefinedPrefix = "";
@@ -46,6 +46,7 @@ export async function transformRLCModel(
46
46
  ): Promise<RLCModel> {
47
47
  const program = dpgContext.program;
48
48
  const options: RLCOptions = dpgContext.rlcOptions!;
49
+ const rlcSourceDir = dpgContext.generationPathDetail?.rlcSourcesDir;
49
50
  const srcPath = path.join(
50
51
  dpgContext.generationPathDetail?.rlcSourcesDir ?? "",
51
52
  options.batch && options.batch.length > 1
@@ -100,7 +101,8 @@ export async function transformRLCModel(
100
101
  importInfo: {
101
102
  internalImports: importSet,
102
103
  runtimeImports: buildRuntimeImports(options.flavor)
103
- }
104
+ },
105
+ rlcSourceDir
104
106
  };
105
107
  model.sampleGroups = transformSampleGroups(
106
108
  model,
@@ -86,7 +86,7 @@ export function getOperationApiVersion(
86
86
  relevantProperty: p.param
87
87
  });
88
88
  required.add(!p.param.optional);
89
- if (p.type !== "header") {
89
+ if (p.type === "query" || p.type === "path") {
90
90
  locations.add(p.type);
91
91
  }
92
92
  const typeString = JSON.stringify(trimUsage(type));
@@ -127,7 +127,7 @@ export function getOperationApiVersion(
127
127
  relevantProperty: p.param
128
128
  });
129
129
  required.add(!p.param.optional);
130
- if (p.type !== "header") {
130
+ if (p.type === "query" || p.type === "path") {
131
131
  locations.add(p.type);
132
132
  }
133
133
  const typeString = JSON.stringify(trimUsage(type));
@@ -177,33 +177,19 @@ function extractSpecialSerializeInfo(
177
177
  dpgContext: SdkContext
178
178
  ) {
179
179
  let hasMultiCollection = false;
180
- let hasPipeCollection = false;
181
- let hasTsvCollection = false;
182
- let hasSsvCollection = false;
183
180
  let hasCsvCollection = false;
184
181
  const clientOperations = listOperationsInOperationGroup(dpgContext, client);
185
182
  for (const clientOp of clientOperations) {
186
183
  const route = getHttpOperationWithCache(dpgContext, clientOp);
187
184
  route.parameters.parameters.forEach((parameter) => {
188
185
  const serializeInfo = getSpecialSerializeInfo(
186
+ dpgContext,
189
187
  parameter.type,
190
188
  (parameter as any).format
191
189
  );
192
190
  hasMultiCollection = hasMultiCollection
193
191
  ? hasMultiCollection
194
192
  : serializeInfo.hasMultiCollection;
195
- hasPipeCollection = hasPipeCollection
196
- ? hasPipeCollection
197
- : serializeInfo.hasPipeCollection;
198
- hasTsvCollection = hasTsvCollection
199
- ? hasTsvCollection
200
- : serializeInfo.hasTsvCollection;
201
- hasSsvCollection = hasSsvCollection
202
- ? hasSsvCollection
203
- : serializeInfo.hasSsvCollection;
204
- hasCsvCollection = hasCsvCollection
205
- ? hasCsvCollection
206
- : serializeInfo.hasCsvCollection;
207
193
  });
208
194
  }
209
195
  const operationGroups = listOperationGroups(dpgContext, client, true);
@@ -216,21 +202,13 @@ function extractSpecialSerializeInfo(
216
202
  const route = getHttpOperationWithCache(dpgContext, op);
217
203
  route.parameters.parameters.forEach((parameter) => {
218
204
  const serializeInfo = getSpecialSerializeInfo(
205
+ dpgContext,
219
206
  parameter.type,
220
207
  (parameter as any).format
221
208
  );
222
209
  hasMultiCollection = hasMultiCollection
223
210
  ? hasMultiCollection
224
211
  : serializeInfo.hasMultiCollection;
225
- hasPipeCollection = hasPipeCollection
226
- ? hasPipeCollection
227
- : serializeInfo.hasPipeCollection;
228
- hasTsvCollection = hasTsvCollection
229
- ? hasTsvCollection
230
- : serializeInfo.hasTsvCollection;
231
- hasSsvCollection = hasSsvCollection
232
- ? hasSsvCollection
233
- : serializeInfo.hasSsvCollection;
234
212
  hasCsvCollection = hasCsvCollection
235
213
  ? hasCsvCollection
236
214
  : serializeInfo.hasCsvCollection;
@@ -239,9 +217,6 @@ function extractSpecialSerializeInfo(
239
217
  }
240
218
  return {
241
219
  hasMultiCollection,
242
- hasPipeCollection,
243
- hasTsvCollection,
244
- hasSsvCollection,
245
220
  hasCsvCollection
246
221
  };
247
222
  }
@@ -29,14 +29,14 @@ import {
29
29
  listOperationGroups,
30
30
  listOperationsInOperationGroup
31
31
  } from "@azure-tools/typespec-client-generator-core";
32
- import { Type, isVoidType } from "@typespec/compiler";
32
+ import { NoTarget, Type, isVoidType } from "@typespec/compiler";
33
33
  import {
34
34
  getBodyType,
35
35
  getFormattedPropertyDoc,
36
36
  getImportedModelName,
37
37
  getSchemaForType,
38
- getSerializeTypeName,
39
38
  getTypeName,
39
+ isArrayType,
40
40
  isBodyRequired
41
41
  } from "../utils/modelUtils.js";
42
42
  import {
@@ -44,8 +44,16 @@ import {
44
44
  getOperationName,
45
45
  getSpecialSerializeInfo
46
46
  } from "../utils/operationUtil.js";
47
-
48
47
  import { SdkContext } from "../utils/interfaces.js";
48
+ import { getParameterSerializationInfo } from "../utils/parameterUtils.js";
49
+ import { reportDiagnostic } from "../lib.js";
50
+
51
+ interface ParameterTransformationOptions {
52
+ apiVersionInfo?: ApiVersionInfo;
53
+ operationGroupName?: string;
54
+ operationName?: string;
55
+ importModels?: Set<string>;
56
+ }
49
57
 
50
58
  export function transformToParameterTypes(
51
59
  client: SdkClient,
@@ -90,20 +98,27 @@ export function transformToParameterTypes(
90
98
  operationName: getOperationName(dpgContext, route.operation),
91
99
  parameters: []
92
100
  };
101
+ const options = {
102
+ apiVersionInfo,
103
+ operationGroupName: rlcParameter.operationGroup,
104
+ operationName: rlcParameter.operationName,
105
+ importModels: outputImportedSet
106
+ };
93
107
  // transform query param
94
108
  const queryParams = transformQueryParameters(
95
109
  dpgContext,
96
110
  parameters,
97
- { apiVersionInfo },
98
- outputImportedSet
111
+ options
99
112
  );
100
113
  // transform path param
101
- const pathParams = transformPathParameters();
114
+ const pathParams = transformPathParameters(dpgContext, parameters, options);
115
+ // TODO: support cookie parameters, https://github.com/Azure/autorest.typescript/issues/2898
116
+ transformCookieParameters(dpgContext, parameters);
102
117
  // transform header param including content-type
103
118
  const headerParams = transformHeaderParameters(
104
119
  dpgContext,
105
120
  parameters,
106
- outputImportedSet
121
+ options
107
122
  );
108
123
  // transform body
109
124
  const bodyType = getBodyType(route);
@@ -130,65 +145,62 @@ function getParameterMetadata(
130
145
  dpgContext: SdkContext,
131
146
  paramType: "query" | "path" | "header",
132
147
  parameter: HttpOperationParameter,
133
- importedModels: Set<string>
148
+ options: ParameterTransformationOptions
134
149
  ): ParameterMetadata {
135
150
  const program = dpgContext.program;
151
+ const importedModels = options.importModels ?? new Set<string>();
136
152
  const schemaContext = [SchemaContext.Exception, SchemaContext.Input];
137
153
  const schema = getSchemaForType(dpgContext, parameter.param.type, {
138
154
  usage: schemaContext,
139
155
  needRef: false,
140
156
  relevantProperty: parameter.param
141
157
  }) as Schema;
142
- let type = getTypeName(schema, schemaContext);
143
158
  const name = getParameterName(parameter.name);
144
159
  let description =
145
160
  getFormattedPropertyDoc(program, parameter.param, schema) ?? "";
146
- if (
147
- type === "string[]" ||
148
- type === "Array<string>" ||
149
- type === "number[]" ||
150
- type === "Array<number>"
151
- ) {
161
+ if (isArrayType(schema)) {
152
162
  const serializeInfo = getSpecialSerializeInfo(
163
+ dpgContext,
153
164
  parameter.type,
154
165
  (parameter as any).format
155
166
  );
156
- if (
157
- serializeInfo.hasMultiCollection ||
158
- serializeInfo.hasPipeCollection ||
159
- serializeInfo.hasSsvCollection ||
160
- serializeInfo.hasTsvCollection ||
161
- serializeInfo.hasCsvCollection
162
- ) {
163
- type = "string";
164
- description += ` This parameter needs to be formatted as ${serializeInfo.collectionInfo.join(
167
+ if (serializeInfo.hasMultiCollection || serializeInfo.hasCsvCollection) {
168
+ description += `${description ? "\n" : ""}This parameter could be formatted as ${serializeInfo.collectionInfo.join(
165
169
  ", "
166
- )} collection, we provide ${serializeInfo.descriptions.join(
170
+ )} collection string, we provide ${serializeInfo.descriptions.join(
167
171
  ", "
168
172
  )} from serializeHelper.ts to help${
169
173
  serializeInfo.hasMultiCollection
170
174
  ? ", you will probably need to set skipUrlEncoding as true when sending the request"
171
175
  : ""
172
- }`;
176
+ }.`;
177
+ }
178
+ if ((parameter as any).format === "tsv") {
179
+ description += `${description ? "\n" : ""}This parameter could be formatted as tsv collection string.`;
173
180
  }
174
181
  }
175
- type =
176
- paramType !== "query" && type !== "string"
177
- ? getSerializeTypeName(dpgContext.program, schema, schemaContext)
178
- : type;
182
+
179
183
  getImportedModelName(schema, schemaContext)?.forEach(
180
184
  importedModels.add,
181
185
  importedModels
182
186
  );
187
+ const serializationType = getParameterSerializationInfo(
188
+ dpgContext,
189
+ parameter,
190
+ schema,
191
+ options.operationGroupName,
192
+ options.operationName
193
+ );
183
194
  return {
184
195
  type: paramType,
185
196
  name,
186
197
  param: {
187
198
  name,
188
- type,
189
- typeName: type,
199
+ type: serializationType.typeName,
200
+ typeName: serializationType.typeName,
190
201
  required: !parameter.param.optional,
191
- description
202
+ description,
203
+ wrapperType: serializationType.wrapperType
192
204
  }
193
205
  };
194
206
  }
@@ -200,11 +212,29 @@ function getParameterName(name: string) {
200
212
  return `"${name}"`;
201
213
  }
202
214
 
215
+ function transformCookieParameters(
216
+ dpgContext: SdkContext,
217
+ parameters: HttpOperationParameters
218
+ ) {
219
+ // TODO: support cookie parameters, https://github.com/Azure/autorest.typescript/issues/2898
220
+ parameters.parameters
221
+ .filter((p) => p.type === "cookie")
222
+ .forEach((p) => {
223
+ reportDiagnostic(dpgContext.program, {
224
+ code: "parameter-type-not-supported",
225
+ format: {
226
+ paramName: p.name,
227
+ paramType: p.type
228
+ },
229
+ target: NoTarget
230
+ });
231
+ });
232
+ }
233
+
203
234
  function transformQueryParameters(
204
235
  dpgContext: SdkContext,
205
236
  parameters: HttpOperationParameters,
206
- options: { apiVersionInfo: ApiVersionInfo | undefined },
207
- importModels: Set<string> = new Set<string>()
237
+ options: ParameterTransformationOptions
208
238
  ): ParameterMetadata[] {
209
239
  const queryParameters = parameters.parameters.filter(
210
240
  (p) =>
@@ -218,7 +248,7 @@ function transformQueryParameters(
218
248
  return [];
219
249
  }
220
250
  return queryParameters.map((qp) =>
221
- getParameterMetadata(dpgContext, "query", qp, importModels)
251
+ getParameterMetadata(dpgContext, "query", qp, options)
222
252
  );
223
253
  }
224
254
 
@@ -226,16 +256,27 @@ function transformQueryParameters(
226
256
  * Only support to take the global path parameter as path parameter
227
257
  * @returns
228
258
  */
229
- function transformPathParameters() {
230
- // TODO
231
- // issue tracked https://github.com/Azure/autorest.typescript/issues/1521
232
- return [];
259
+ function transformPathParameters(
260
+ dpgContext: SdkContext,
261
+ parameters: HttpOperationParameters,
262
+ options: ParameterTransformationOptions
263
+ ) {
264
+ // build wrapper path parameters
265
+ const pathParameters = parameters.parameters.filter((p) => p.type === "path");
266
+ if (!pathParameters.length) {
267
+ return [];
268
+ }
269
+ // only need to build path parameters for wrapper type
270
+ const params = pathParameters
271
+ .map((qp) => getParameterMetadata(dpgContext, "path", qp, options))
272
+ .filter((p) => p.param.wrapperType);
273
+ return params;
233
274
  }
234
275
 
235
276
  export function transformHeaderParameters(
236
277
  dpgContext: SdkContext,
237
278
  parameters: HttpOperationParameters,
238
- importedModels: Set<string>
279
+ options: ParameterTransformationOptions
239
280
  ): ParameterMetadata[] {
240
281
  const headerParameters = parameters.parameters.filter(
241
282
  (p) => p.type === "header"
@@ -244,7 +285,7 @@ export function transformHeaderParameters(
244
285
  return [];
245
286
  }
246
287
  return headerParameters.map((qp) =>
247
- getParameterMetadata(dpgContext, "header", qp, importedModels)
288
+ getParameterMetadata(dpgContext, "header", qp, options)
248
289
  );
249
290
  }
250
291
 
@@ -31,12 +31,12 @@ import {
31
31
  import {
32
32
  getImportedModelName,
33
33
  getSchemaForType,
34
- getTypeName,
35
34
  isBodyRequired
36
35
  } from "../utils/modelUtils.js";
37
36
 
38
37
  import { SdkContext } from "../utils/interfaces.js";
39
38
  import { getDoc } from "@typespec/compiler";
39
+ import { getParameterSerializationInfo } from "../utils/parameterUtils.js";
40
40
 
41
41
  export function transformPaths(
42
42
  client: SdkClient,
@@ -133,15 +133,33 @@ function transformOperation(
133
133
  .filter((p) => p.type === "path")
134
134
  .map((p) => {
135
135
  const schemaUsage = [SchemaContext.Input, SchemaContext.Exception];
136
+ const options = {
137
+ usage: schemaUsage,
138
+ needRef: false,
139
+ relevantProperty: p.param
140
+ };
136
141
  const schema = p.param.sourceProperty
137
- ? getSchemaForType(dpgContext, p.param.sourceProperty?.type)
138
- : getSchemaForType(dpgContext, p.param.type);
142
+ ? getSchemaForType(
143
+ dpgContext,
144
+ p.param.sourceProperty?.type,
145
+
146
+ options
147
+ )
148
+ : getSchemaForType(dpgContext, p.param.type, options);
139
149
  const importedNames = getImportedModelName(schema, schemaUsage) ?? [];
140
150
  importedNames.forEach(importSet.add, importSet);
151
+ const serializationType = getParameterSerializationInfo(
152
+ dpgContext,
153
+ p,
154
+ schema,
155
+ operationGroupName,
156
+ method.operationName
157
+ );
141
158
  return {
142
159
  name: p.name,
143
- type: getTypeName(schema, schemaUsage),
144
- description: getDoc(program, p.param)
160
+ type: serializationType.typeName,
161
+ description: getDoc(program, p.param) ?? "",
162
+ wrapperType: serializationType.wrapperType
145
163
  };
146
164
  }),
147
165
  operationGroupName: getOperationGroupName(dpgContext, route),