@azure-tools/typespec-ts 0.41.1 → 0.42.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 (39) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/src/framework/declaration.d.ts +6 -5
  3. package/dist/src/framework/declaration.d.ts.map +1 -1
  4. package/dist/src/framework/declaration.js +16 -6
  5. package/dist/src/framework/declaration.js.map +1 -1
  6. package/dist/src/index.d.ts.map +1 -1
  7. package/dist/src/index.js +3 -4
  8. package/dist/src/index.js.map +1 -1
  9. package/dist/src/modular/buildClassicalClient.js +3 -1
  10. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  11. package/dist/src/modular/emitModels.d.ts.map +1 -1
  12. package/dist/src/modular/emitModels.js +4 -4
  13. package/dist/src/modular/emitModels.js.map +1 -1
  14. package/dist/src/modular/emitSamples.js +4 -4
  15. package/dist/src/modular/emitSamples.js.map +1 -1
  16. package/dist/src/modular/helpers/clientHelpers.d.ts.map +1 -1
  17. package/dist/src/modular/helpers/clientHelpers.js +4 -11
  18. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  19. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  20. package/dist/src/modular/helpers/operationHelpers.js +7 -9
  21. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  22. package/dist/src/modular/serialization/buildDeserializerFunction.js +5 -5
  23. package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
  24. package/dist/src/modular/serialization/buildSerializerFunction.js +5 -5
  25. package/dist/src/modular/serialization/buildSerializerFunction.js.map +1 -1
  26. package/dist/src/utils/clientUtils.js +1 -1
  27. package/dist/src/utils/clientUtils.js.map +1 -1
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +11 -11
  30. package/src/framework/declaration.ts +28 -13
  31. package/src/index.ts +3 -4
  32. package/src/modular/buildClassicalClient.ts +5 -1
  33. package/src/modular/emitModels.ts +4 -4
  34. package/src/modular/emitSamples.ts +4 -4
  35. package/src/modular/helpers/clientHelpers.ts +2 -7
  36. package/src/modular/helpers/operationHelpers.ts +12 -12
  37. package/src/modular/serialization/buildDeserializerFunction.ts +5 -10
  38. package/src/modular/serialization/buildSerializerFunction.ts +5 -10
  39. package/src/utils/clientUtils.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.41.1",
3
+ "version": "0.42.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.24-dev.0",
22
- "@typespec/spector": "0.1.0-alpha.16-dev.0",
23
- "@typespec/spec-api": "0.1.0-alpha.7-dev.0",
24
- "@azure-tools/azure-http-specs": "0.1.0-alpha.20-dev.0",
25
- "@azure-tools/typespec-autorest": "^0.57.0",
21
+ "@typespec/http-specs": "0.1.0-alpha.24-dev.2",
22
+ "@typespec/spector": "0.1.0-alpha.16-dev.2",
23
+ "@typespec/spec-api": "0.1.0-alpha.7-dev.1",
24
+ "@azure-tools/azure-http-specs": "0.1.0-alpha.22",
25
+ "@azure-tools/typespec-autorest": "^0.57.1",
26
26
  "@azure-tools/typespec-azure-core": "^0.57.0",
27
- "@azure-tools/typespec-azure-resource-manager": "^0.57.0",
28
- "@azure-tools/typespec-client-generator-core": "^0.57.1",
27
+ "@azure-tools/typespec-azure-resource-manager": "^0.57.2",
28
+ "@azure-tools/typespec-client-generator-core": "^0.57.3",
29
29
  "@azure/abort-controller": "^2.1.2",
30
30
  "@azure/core-auth": "^1.6.0",
31
31
  "@azure/core-lro": "^3.1.0",
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "peerDependencies": {
70
70
  "@azure-tools/typespec-azure-core": "^0.57.0",
71
- "@azure-tools/typespec-client-generator-core": "^0.57.1",
71
+ "@azure-tools/typespec-client-generator-core": "^0.57.3",
72
72
  "@typespec/compiler": "^1.1.0",
73
73
  "@typespec/http": "^1.1.0",
74
74
  "@typespec/rest": "^0.71.0",
@@ -76,7 +76,7 @@
76
76
  "@typespec/xml": "^0.71.0"
77
77
  },
78
78
  "dependencies": {
79
- "@azure-tools/rlc-common": "^0.41.1",
79
+ "@azure-tools/rlc-common": "^0.42.0",
80
80
  "fs-extra": "^11.1.0",
81
81
  "lodash": "^4.17.21",
82
82
  "prettier": "^3.3.3",
@@ -145,6 +145,6 @@
145
145
  "stop-test-server": "npx tsp-spector server stop",
146
146
  "unit-test": "npm-run-all --parallel unit-test:rlc unit-test:modular",
147
147
  "unit-test:rlc": "cross-env TS_NODE_PROJECT=tsconfig.json mocha -r ts-node/register --experimental-specifier-resolution=node --experimental-modules=true --timeout 36000 './test/unit/**/*.spec.ts'",
148
- "unit-test:modular": "cross-env TS_NODE_PROJECT=tsconfig.test.json mocha -r ts-node/register --experimental-specifier-resolution=node --experimental-modules=true --no-timeout './test/modularUnit/**/*.spec.ts'"
148
+ "unit-test:modular": "cross-env TS_NODE_PROJECT=tsconfig.test.json mocha -r ts-node/register --experimental-specifier-resolution=node --experimental-modules=true --no-timeout './test/modularUnit/**/*.spec.ts' --reporter-options maxDiffSize=20000"
149
149
  }
150
150
  }
@@ -32,38 +32,46 @@ export function addDeclaration(
32
32
  sourceFile: SourceFile,
33
33
  declaration: ClassDeclarationStructure,
34
34
  refkey: unknown
35
- ): ClassDeclaration;
35
+ ): void;
36
36
 
37
37
  export function addDeclaration(
38
38
  sourceFile: SourceFile,
39
39
  declaration: EnumDeclarationStructure,
40
40
  refkey: unknown
41
- ): EnumDeclaration;
41
+ ): void;
42
42
 
43
43
  export function addDeclaration(
44
44
  sourceFile: SourceFile,
45
45
  declaration: FunctionDeclarationStructure,
46
46
  refkey: unknown
47
- ): FunctionDeclaration;
47
+ ): void;
48
48
 
49
49
  export function addDeclaration(
50
50
  sourceFile: SourceFile,
51
51
  declaration: InterfaceDeclarationStructure,
52
52
  refkey: unknown
53
- ): InterfaceDeclaration;
53
+ ): void;
54
54
 
55
55
  export function addDeclaration(
56
56
  sourceFile: SourceFile,
57
57
  declaration: TypeAliasDeclarationStructure,
58
58
  refkey: unknown
59
- ): TypeAliasDeclaration;
59
+ ): void;
60
60
  export function addDeclaration(
61
61
  sourceFile: SourceFile,
62
- declaration: DeclarationStructures,
62
+ declaration: string,
63
63
  refkey: unknown
64
- ): Declarations {
64
+ ): void;
65
+ export function addDeclaration(
66
+ sourceFile: SourceFile,
67
+ input: DeclarationStructures | string,
68
+ refkey: unknown
69
+ ): void {
65
70
  const binder = useBinder();
66
-
71
+ const declaration: DeclarationStructures =
72
+ typeof input === "string"
73
+ ? ({ name: input, kind: StructureKind.TypeAlias } as any)
74
+ : input;
67
75
  if (!declaration.name) {
68
76
  throw new Error(
69
77
  `Declaration must have a name ${JSON.stringify(declaration)}`
@@ -82,15 +90,22 @@ export function addDeclaration(
82
90
 
83
91
  switch (trackedDeclaration.kind) {
84
92
  case StructureKind.Class:
85
- return sourceFile.addClass(trackedDeclaration);
93
+ sourceFile.addClass(trackedDeclaration);
94
+ break;
86
95
  case StructureKind.Enum:
87
- return sourceFile.addEnum(trackedDeclaration);
96
+ sourceFile.addEnum(trackedDeclaration);
97
+ break;
88
98
  case StructureKind.Function:
89
- return sourceFile.addFunction(trackedDeclaration);
99
+ sourceFile.addFunction(trackedDeclaration);
100
+ break;
90
101
  case StructureKind.Interface:
91
- return sourceFile.addInterface(trackedDeclaration);
102
+ sourceFile.addInterface(trackedDeclaration);
103
+ break;
92
104
  case StructureKind.TypeAlias:
93
- return sourceFile.addTypeAlias(trackedDeclaration);
105
+ if (trackedDeclaration.type) {
106
+ sourceFile.addTypeAlias(trackedDeclaration);
107
+ }
108
+ break;
94
109
  default:
95
110
  throw new Error(
96
111
  `Unsupported declaration kind ${(trackedDeclaration as any).kind}`
package/src/index.ts CHANGED
@@ -199,7 +199,7 @@ export async function $onEmit(context: EmitContext) {
199
199
  options.generateTest =
200
200
  options.generateTest === true ||
201
201
  (options.generateTest === undefined &&
202
- !hasTestFolder &&
202
+ (!hasTestFolder || (options.azureSdkForJs && options.azureArm)) &&
203
203
  isAzurePackage({ options: options }));
204
204
  dpgContext.rlcOptions = options;
205
205
  }
@@ -403,8 +403,7 @@ export async function $onEmit(context: EmitContext) {
403
403
  );
404
404
  const hasPackageFile = await existsSync(existingPackageFilePath);
405
405
  const shouldGenerateMetadata =
406
- option.generateMetadata === true ||
407
- (option.generateMetadata === undefined && !hasPackageFile);
406
+ option.generateMetadata === true || !hasPackageFile;
408
407
  const existingTestFolderPath = join(
409
408
  dpgContext.generationPathDetail?.metadataDir ?? "",
410
409
  "test"
@@ -519,7 +518,7 @@ export async function $onEmit(context: EmitContext) {
519
518
  }
520
519
 
521
520
  // Generate test relevant files
522
- if (option.generateTest && isAzureFlavor) {
521
+ if (option.generateTest && isAzureFlavor && !hasTestFolder) {
523
522
  await emitContentByBuilder(
524
523
  program,
525
524
  [buildRecordedClientFile, buildSampleTest],
@@ -308,7 +308,11 @@ function addChildClient(
308
308
  ${parentParams
309
309
  .filter((p) => !p.name.includes("options"))
310
310
  .map((p) => `this._clientParams.${p.name}`)
311
- .join(",")},
311
+ .join(",")}${
312
+ parentParams.filter((p) => !p.name.includes("options")).length > 0
313
+ ? ","
314
+ : ""
315
+ }
312
316
  ${diffParams
313
317
  .filter((p) => p.name !== "options")
314
318
  .map((p) => `${p.name}`)
@@ -230,8 +230,10 @@ function emitType(context: SdkContext, type: SdkType, sourceFile: SourceFile) {
230
230
  addDeclaration(sourceFile, unionType, type);
231
231
  addSerializationFunctions(context, type, sourceFile);
232
232
  } else if (type.kind === "dict") {
233
+ addDeclaration(sourceFile, normalizeModelName(context, type), type);
233
234
  addSerializationFunctions(context, type, sourceFile);
234
235
  } else if (type.kind === "array") {
236
+ addDeclaration(sourceFile, normalizeModelName(context, type), type);
235
237
  addSerializationFunctions(context, type, sourceFile);
236
238
  } else if (type.kind === "nullable") {
237
239
  const nullableType = buildNullableType(context, type);
@@ -320,8 +322,7 @@ function addSerializationFunctions(
320
322
  if (
321
323
  serializationFunction &&
322
324
  typeof serializationFunction !== "string" &&
323
- serializationFunction.name &&
324
- !sourceFile.getFunction(serializationFunction.name)
325
+ serializationFunction.name
325
326
  ) {
326
327
  addDeclaration(sourceFile, serializationFunction, serializerRefkey);
327
328
  }
@@ -333,8 +334,7 @@ function addSerializationFunctions(
333
334
  if (
334
335
  deserializationFunction &&
335
336
  typeof deserializationFunction !== "string" &&
336
- deserializationFunction.name &&
337
- !sourceFile.getFunction(deserializationFunction.name)
337
+ deserializationFunction.name
338
338
  ) {
339
339
  addDeclaration(sourceFile, deserializationFunction, deserailizerRefKey);
340
340
  }
@@ -323,9 +323,9 @@ function prepareExampleParameters(
323
323
  }
324
324
  // required/optional body parameters
325
325
  const bodyParam = method.operation.bodyParam;
326
- const bodyName = bodyParam?.serializedName;
327
- const bodyExample = parameterMap[bodyName ?? ""];
328
- if (bodyName && bodyExample && bodyExample.value) {
326
+ const bodySerializeName = bodyParam?.serializedName;
327
+ const bodyExample = parameterMap[bodySerializeName ?? ""];
328
+ if (bodySerializeName && bodyExample && bodyExample.value) {
329
329
  if (
330
330
  isSpreadBodyParameter(bodyParam) &&
331
331
  bodyParam.type.kind === "model" &&
@@ -348,7 +348,7 @@ function prepareExampleParameters(
348
348
  } else {
349
349
  result.push(
350
350
  prepareExampleValue(
351
- bodyName,
351
+ bodyParam.name,
352
352
  bodyExample.value,
353
353
  bodyParam.optional,
354
354
  bodyParam.onClient
@@ -170,13 +170,8 @@ export function buildGetClientEndpointParam(
170
170
  dpgContext: SdkContext,
171
171
  client: SdkClientType<SdkServiceOperation>
172
172
  ): string {
173
- let coreEndpointParam = "";
174
- if (dpgContext.rlcOptions?.flavor === "azure") {
175
- coreEndpointParam = `options.endpoint ?? options.baseUrl`;
176
- } else {
177
- // unbranded does not have the deprecated baseUrl parameter
178
- coreEndpointParam = `options.endpoint`;
179
- }
173
+ const coreEndpointParam = `options.endpoint`;
174
+
180
175
  // Special case: endpoint URL not defined
181
176
  const endpointParam = getClientParameters(client, dpgContext, {
182
177
  onClientOnly: true,
@@ -678,7 +678,7 @@ function getHeaderAndBodyParameters(
678
678
  return "";
679
679
  }
680
680
  const operationParameters = operation.operation.parameters.filter(
681
- (p) => (!p.onClient || p.isApiVersionParam) && !isContentType(p)
681
+ (p) => !isContentType(p)
682
682
  );
683
683
 
684
684
  const contentTypeParameter =
@@ -782,7 +782,11 @@ function buildBodyParameter(
782
782
  true
783
783
  );
784
784
 
785
- const bodyParamName = normalizeName(bodyParameter.name, NameType.Parameter);
785
+ const bodyParamName = normalizeName(
786
+ bodyParameter.name,
787
+ NameType.Parameter,
788
+ true
789
+ );
786
790
  const bodyNameExpression = bodyParameter.optional
787
791
  ? `${optionalParamName}["${bodyParamName}"]`
788
792
  : bodyParamName;
@@ -1016,7 +1020,7 @@ function getPathParameters(
1016
1020
  for (const param of operation.operation.parameters) {
1017
1021
  if (param.kind === "path") {
1018
1022
  pathParams.push(
1019
- `"${param.serializedName}": ${getPathParamExpr(param, getDefaultValue(param) as string, optionalParamName)}`
1023
+ `"${param.serializedName}": ${getPathParamExpr(param.correspondingMethodParams[0]!, getDefaultValue(param) as string, optionalParamName)}`
1020
1024
  );
1021
1025
  }
1022
1026
  }
@@ -1035,7 +1039,7 @@ function getQueryParameters(
1035
1039
  return [];
1036
1040
  }
1037
1041
  const operationParameters = operation.operation.parameters.filter(
1038
- (p) => (!p.onClient || p.isApiVersionParam) && !isContentType(p)
1042
+ (p) => !isContentType(p)
1039
1043
  );
1040
1044
  const parametersImplementation: Record<
1041
1045
  "query",
@@ -1075,7 +1079,7 @@ function escapeUriTemplateParamName(name: string) {
1075
1079
  }
1076
1080
 
1077
1081
  function getPathParamExpr(
1078
- param: SdkServiceParameter,
1082
+ param: SdkModelPropertyType,
1079
1083
  defaultValue?: string,
1080
1084
  optionalParamName: string = "options"
1081
1085
  ) {
@@ -1546,14 +1550,10 @@ export function getPropertyFullName(
1546
1550
  * @param operation The operation
1547
1551
  */
1548
1552
  export function getExpectedStatuses(operation: ServiceOperation): string {
1549
- const statusCodes = operation.operation.responses.map((x) => x.statusCodes);
1553
+ let statusCodes = operation.operation.responses.map((x) => x.statusCodes);
1550
1554
  // LROs may call the same path but with GET to get the operation status.
1551
- if (
1552
- isLroOnlyOperation(operation) &&
1553
- operation.operation.verb !== "get" &&
1554
- !statusCodes.includes(200)
1555
- ) {
1556
- statusCodes.push(200);
1555
+ if (isLroOnlyOperation(operation) && operation.operation.verb !== "get") {
1556
+ statusCodes = Array.from(new Set([...statusCodes, 200, 202]));
1557
1557
  }
1558
1558
 
1559
1559
  return `[${statusCodes.map((x) => `"${x}"`).join(", ")}]`;
@@ -122,7 +122,7 @@ function buildPolymorphicDeserializer(
122
122
  type: "any"
123
123
  }
124
124
  ],
125
- returnType: normalizeModelName(context, type),
125
+ returnType: resolveReference(refkey(type, "polymorphicType")),
126
126
  statements: []
127
127
  };
128
128
  if (!type.discriminatorProperty) {
@@ -249,7 +249,7 @@ function buildDiscriminatedUnionDeserializer(
249
249
  type: "any"
250
250
  }
251
251
  ],
252
- returnType: normalizeModelName(context, type),
252
+ returnType: resolveReference(refkey(type, "polymorphicType")),
253
253
  statements: output.join("\n")
254
254
  };
255
255
  return deserializerFunction;
@@ -290,7 +290,7 @@ function buildUnionDeserializer(
290
290
  type: "any"
291
291
  }
292
292
  ],
293
- returnType: normalizeModelName(context, type),
293
+ returnType: resolveReference(refkey(type)),
294
294
  statements: ["return item;"]
295
295
  };
296
296
  return deserializerFunction;
@@ -326,12 +326,7 @@ function buildModelTypeDeserializer(
326
326
  type: "any"
327
327
  }
328
328
  ],
329
- returnType: normalizeModelName(
330
- context,
331
- type,
332
- NameType.Interface,
333
- options.skipDiscriminatedUnionSuffix
334
- ),
329
+ returnType: resolveReference(refkey(type)),
335
330
  statements: ["return item;"]
336
331
  };
337
332
  const nullabilityPrefix = "";
@@ -436,7 +431,7 @@ function buildDictTypeDeserializer(
436
431
  type: "Record<string, any>"
437
432
  }
438
433
  ],
439
- returnType: `Record<string, ${normalizeModelName(context, type.valueType as any) ?? "any"}>`,
434
+ returnType: `Record<string, ${resolveReference(refkey(type.valueType)) ?? "any"}>`,
440
435
  statements: [
441
436
  `
442
437
  const result: Record<string, any> = {};
@@ -127,7 +127,7 @@ function buildPolymorphicSerializer(
127
127
  parameters: [
128
128
  {
129
129
  name: "item",
130
- type: normalizeModelName(context, type)
130
+ type: resolveReference(refkey(type, "polymorphicType"))
131
131
  }
132
132
  ],
133
133
  returnType: "any",
@@ -253,7 +253,7 @@ function buildDiscriminatedUnionSerializer(
253
253
  parameters: [
254
254
  {
255
255
  name: "item",
256
- type: normalizeModelName(context, type)
256
+ type: resolveReference(refkey(type, "polymorphicType"))
257
257
  }
258
258
  ],
259
259
  returnType: "any",
@@ -294,7 +294,7 @@ function buildUnionSerializer(
294
294
  parameters: [
295
295
  {
296
296
  name: "item",
297
- type: normalizeModelName(context, type)
297
+ type: resolveReference(refkey(type))
298
298
  }
299
299
  ],
300
300
  returnType: "any",
@@ -330,12 +330,7 @@ function buildModelTypeSerializer(
330
330
  parameters: [
331
331
  {
332
332
  name: "item",
333
- type: normalizeModelName(
334
- context,
335
- type,
336
- NameType.Interface,
337
- options.skipDiscriminatedUnionSuffix
338
- )
333
+ type: resolveReference(refkey(type))
339
334
  }
340
335
  ],
341
336
  returnType: "any",
@@ -497,7 +492,7 @@ function buildDictTypeSerializer(
497
492
  parameters: [
498
493
  {
499
494
  name: "item",
500
- type: `Record<string, ${normalizeModelName(context, type.valueType as any) ?? "any"}>`
495
+ type: `Record<string, ${resolveReference(type.valueType) ?? "any"}>`
501
496
  }
502
497
  ],
503
498
  returnType: "Record<string, any>",
@@ -85,7 +85,7 @@ export function getModularClientOptions(
85
85
  ) {
86
86
  const [hierarchy, client] = clientMap;
87
87
  const clientOptions: ModularClientOptions = {
88
- rlcClientName: `${client.name.replace("Client", "")}Context`
88
+ rlcClientName: `${client.name.replace(/Client$/, "")}Context`
89
89
  };
90
90
  clientOptions.subfolder = hierarchy.join("/");
91
91
  return clientOptions;