@azure-tools/typespec-ts 0.15.0 → 0.16.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 (98) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +14 -17
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/lib.d.ts.map +1 -1
  6. package/dist/src/lib.js +3 -3
  7. package/dist/src/lib.js.map +1 -1
  8. package/dist/src/modular/buildClassicalClient.d.ts +2 -3
  9. package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
  10. package/dist/src/modular/buildClassicalClient.js +26 -12
  11. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  12. package/dist/src/modular/buildClientContext.d.ts +3 -3
  13. package/dist/src/modular/buildClientContext.d.ts.map +1 -1
  14. package/dist/src/modular/buildClientContext.js +5 -4
  15. package/dist/src/modular/buildClientContext.js.map +1 -1
  16. package/dist/src/modular/buildCodeModel.d.ts +3 -2
  17. package/dist/src/modular/buildCodeModel.d.ts.map +1 -1
  18. package/dist/src/modular/buildCodeModel.js +141 -54
  19. package/dist/src/modular/buildCodeModel.js.map +1 -1
  20. package/dist/src/modular/buildOperations.d.ts +2 -2
  21. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  22. package/dist/src/modular/buildOperations.js +15 -8
  23. package/dist/src/modular/buildOperations.js.map +1 -1
  24. package/dist/src/modular/buildProjectFiles.js +2 -2
  25. package/dist/src/modular/buildProjectFiles.js.map +1 -1
  26. package/dist/src/modular/buildRootIndex.d.ts +4 -4
  27. package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
  28. package/dist/src/modular/buildRootIndex.js +12 -5
  29. package/dist/src/modular/buildRootIndex.js.map +1 -1
  30. package/dist/src/modular/buildSubpathIndex.d.ts +2 -2
  31. package/dist/src/modular/buildSubpathIndex.d.ts.map +1 -1
  32. package/dist/src/modular/buildSubpathIndex.js +7 -4
  33. package/dist/src/modular/buildSubpathIndex.js.map +1 -1
  34. package/dist/src/modular/emitModels.d.ts +3 -3
  35. package/dist/src/modular/emitModels.d.ts.map +1 -1
  36. package/dist/src/modular/emitModels.js +28 -18
  37. package/dist/src/modular/emitModels.js.map +1 -1
  38. package/dist/src/modular/helpers/clientHelpers.js +1 -1
  39. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  40. package/dist/src/modular/helpers/operationHelpers.d.ts +1 -1
  41. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  42. package/dist/src/modular/helpers/operationHelpers.js +140 -77
  43. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  44. package/dist/src/modular/helpers/typeHelpers.d.ts +2 -2
  45. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  46. package/dist/src/modular/helpers/typeHelpers.js +13 -7
  47. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  48. package/dist/src/modular/modularCodeModel.d.ts +11 -0
  49. package/dist/src/modular/modularCodeModel.d.ts.map +1 -1
  50. package/dist/src/transform/transformHelperFunctionDetails.js +3 -4
  51. package/dist/src/transform/transformHelperFunctionDetails.js.map +1 -1
  52. package/dist/src/transform/transformParameters.d.ts +0 -10
  53. package/dist/src/transform/transformParameters.d.ts.map +1 -1
  54. package/dist/src/transform/transformParameters.js +7 -51
  55. package/dist/src/transform/transformParameters.js.map +1 -1
  56. package/dist/src/transform/transformResponses.js +3 -4
  57. package/dist/src/transform/transformResponses.js.map +1 -1
  58. package/dist/src/transform/transformSchemas.d.ts.map +1 -1
  59. package/dist/src/transform/transformSchemas.js +4 -8
  60. package/dist/src/transform/transformSchemas.js.map +1 -1
  61. package/dist/src/transform/transformTelemetryInfo.d.ts.map +1 -1
  62. package/dist/src/transform/transformTelemetryInfo.js +3 -10
  63. package/dist/src/transform/transformTelemetryInfo.js.map +1 -1
  64. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  65. package/dist/src/transform/transfromRLCOptions.js +48 -9
  66. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  67. package/dist/src/utils/modelUtils.d.ts +2 -1
  68. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  69. package/dist/src/utils/modelUtils.js +83 -73
  70. package/dist/src/utils/modelUtils.js.map +1 -1
  71. package/dist/src/utils/operationUtil.d.ts +15 -1
  72. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  73. package/dist/src/utils/operationUtil.js +82 -3
  74. package/dist/src/utils/operationUtil.js.map +1 -1
  75. package/dist/tsconfig.tsbuildinfo +1 -1
  76. package/package.json +13 -11
  77. package/src/index.ts +24 -51
  78. package/src/lib.ts +3 -3
  79. package/src/modular/buildClassicalClient.ts +29 -16
  80. package/src/modular/buildClientContext.ts +8 -9
  81. package/src/modular/buildCodeModel.ts +183 -60
  82. package/src/modular/buildOperations.ts +16 -11
  83. package/src/modular/buildProjectFiles.ts +2 -2
  84. package/src/modular/buildRootIndex.ts +19 -12
  85. package/src/modular/buildSubpathIndex.ts +10 -8
  86. package/src/modular/emitModels.ts +35 -24
  87. package/src/modular/helpers/clientHelpers.ts +1 -1
  88. package/src/modular/helpers/operationHelpers.ts +231 -118
  89. package/src/modular/helpers/typeHelpers.ts +14 -7
  90. package/src/modular/modularCodeModel.ts +11 -0
  91. package/src/transform/transformHelperFunctionDetails.ts +10 -4
  92. package/src/transform/transformParameters.ts +15 -57
  93. package/src/transform/transformResponses.ts +2 -4
  94. package/src/transform/transformSchemas.ts +5 -9
  95. package/src/transform/transformTelemetryInfo.ts +4 -18
  96. package/src/transform/transfromRLCOptions.ts +67 -9
  97. package/src/utils/modelUtils.ts +81 -72
  98. package/src/utils/operationUtil.ts +121 -4
@@ -27,10 +27,8 @@ import {
27
27
  isStringType,
28
28
  getPropertyType,
29
29
  isNumericType,
30
- getFormat,
31
30
  getMinItems,
32
31
  getMaxItems,
33
- EmitContext,
34
32
  listServices,
35
33
  Union,
36
34
  Type,
@@ -38,12 +36,12 @@ import {
38
36
  getProjectedName,
39
37
  isNullType,
40
38
  getEncode,
41
- isTemplateDeclarationOrInstance
39
+ isTemplateDeclarationOrInstance,
40
+ getFormat
42
41
  } from "@typespec/compiler";
43
42
  import {
44
43
  getAuthentication,
45
44
  getHeaderFieldName,
46
- getHttpOperation,
47
45
  getPathParamName,
48
46
  getQueryParamName,
49
47
  getServers,
@@ -54,7 +52,8 @@ import {
54
52
  HttpServer,
55
53
  isStatusCode,
56
54
  HttpOperation,
57
- isHeader
55
+ isHeader,
56
+ getHttpOperation
58
57
  } from "@typespec/http";
59
58
  import { getAddedOnVersions } from "@typespec/versioning";
60
59
  import {
@@ -65,7 +64,6 @@ import {
65
64
  isApiVersion,
66
65
  getDefaultApiVersion,
67
66
  getClientNamespaceString,
68
- createSdkContext,
69
67
  getSdkUnion,
70
68
  getAllModels,
71
69
  SdkSimpleType,
@@ -82,15 +80,24 @@ import {
82
80
  Type as HrlcType,
83
81
  Header
84
82
  } from "./modularCodeModel.js";
85
- import { transformRLCOptions } from "../transform/transfromRLCOptions.js";
86
- import { getEnrichedDefaultApiVersion } from "../utils/modelUtils.js";
83
+ import {
84
+ getEnrichedDefaultApiVersion,
85
+ isAzureCoreErrorType
86
+ } from "../utils/modelUtils.js";
87
87
  import { camelToSnakeCase, toCamelCase } from "../utils/casingUtils.js";
88
- import { RLCModel, getClientName } from "@azure-tools/rlc-common";
88
+ import {
89
+ RLCModel,
90
+ getClientName,
91
+ NameType,
92
+ normalizeName
93
+ } from "@azure-tools/rlc-common";
89
94
  import {
90
95
  getOperationGroupName,
91
- getOperationName
96
+ getOperationName,
97
+ isIgnoredHeaderParam
92
98
  } from "../utils/operationUtil.js";
93
99
  import { SdkContext } from "../utils/interfaces.js";
100
+ import { Project } from "ts-morph";
94
101
 
95
102
  interface HttpServerParameter {
96
103
  type: "endpointPath";
@@ -148,7 +155,8 @@ function isSimpleType(
148
155
  getMaxValue,
149
156
  getMinLength,
150
157
  getMaxLength,
151
- getPattern
158
+ getPattern,
159
+ getEncode
152
160
  ];
153
161
  for (const func of funcs) {
154
162
  if (func(program, type)) {
@@ -187,7 +195,7 @@ function handleDiscriminator(context: SdkContext, type: Model, model: any) {
187
195
  }
188
196
  }
189
197
  }
190
- // it is not included in properties of cadl but needed by python codegen
198
+ // it is not included in properties of typespec but needed by python codegen
191
199
  if (discriminatorProperty) {
192
200
  const discriminatorType = { ...discriminatorProperty.type };
193
201
  discriminatorType.value = null;
@@ -270,8 +278,7 @@ function getType(
270
278
  options: { disableEffectiveModel?: boolean } = {}
271
279
  ): any {
272
280
  // don't cache simple type(string, int, etc) since decorators may change the result
273
- const enableCache =
274
- !isSimpleType(context.program, type) && !isEmptyModel(type);
281
+ const enableCache = !isSimpleType(context.program, type);
275
282
  const effectiveModel =
276
283
  !options.disableEffectiveModel &&
277
284
  (type.kind === "Model" || type.kind === "Union")
@@ -291,6 +298,10 @@ function getType(
291
298
  newValue = emitType(context, type);
292
299
  }
293
300
 
301
+ if (type.kind === "ModelProperty" || type.kind === "Scalar") {
302
+ newValue = applyEncoding(context.program, type, newValue);
303
+ }
304
+
294
305
  if (enableCache) {
295
306
  typesMap.set(effectiveModel, newValue);
296
307
  if (type.kind === "Union") {
@@ -328,6 +339,7 @@ type ParamBase = {
328
339
  addedOn: string | undefined;
329
340
  clientName: string;
330
341
  inOverload: boolean;
342
+ format?: string;
331
343
  };
332
344
  function emitParamBase(
333
345
  program: Program,
@@ -337,12 +349,15 @@ function emitParamBase(
337
349
  let name: string;
338
350
  let description: string = "";
339
351
  let addedOn: string | undefined;
352
+ let format: string | undefined;
340
353
 
341
354
  if (parameter.kind === "ModelProperty") {
355
+ const newParameter = applyEncoding(program, parameter, parameter);
342
356
  optional = parameter.optional;
343
357
  name = parameter.name;
344
358
  description = getDocStr(program, parameter);
345
359
  addedOn = getAddedOnVersion(program, parameter);
360
+ format = newParameter.format;
346
361
  } else {
347
362
  optional = false;
348
363
  name = "body";
@@ -353,7 +368,8 @@ function emitParamBase(
353
368
  description,
354
369
  addedOn,
355
370
  clientName: applyCasing(name, { casing: CASING }),
356
- inOverload: false
371
+ inOverload: false,
372
+ format
357
373
  };
358
374
  }
359
375
 
@@ -421,7 +437,6 @@ function emitBodyParameter(
421
437
  const type = getType(context, getBodyType(context.program, httpOperation), {
422
438
  disableEffectiveModel: true
423
439
  });
424
-
425
440
  if (type.type === "model" && type.name === "") {
426
441
  type.name = capitalize(httpOperation.operation.name) + "Request";
427
442
  }
@@ -459,9 +474,10 @@ function emitParameter(
459
474
  const paramMap: any = {
460
475
  restApiName: parameter.name,
461
476
  location: parameter.type,
462
- type: type,
477
+ type: base.format ? { ...type, format: base.format } : type,
463
478
  implementation: implementation,
464
- skipUrlEncoding: parameter.type === "endpointPath"
479
+ skipUrlEncoding: parameter.type === "endpointPath",
480
+ format: (parameter as any).format ?? base.format
465
481
  };
466
482
 
467
483
  if (paramMap.type.type === "constant") {
@@ -550,23 +566,6 @@ function emitResponseHeaders(
550
566
  return retval;
551
567
  }
552
568
 
553
- function isAzureCoreErrorType(t?: Type): boolean {
554
- if (
555
- t?.kind !== "Model" ||
556
- !["Error", "ErrorResponse", "InnerError"].includes(t.name)
557
- )
558
- return false;
559
- const namespaces = ".Azure.Core.Foundations".split(".");
560
- while (
561
- namespaces.length > 0 &&
562
- (t?.kind === "Model" || t?.kind === "Namespace") &&
563
- t.namespace?.name === namespaces.pop()
564
- ) {
565
- t = t.namespace;
566
- }
567
- return namespaces.length == 0;
568
- }
569
-
570
569
  function emitResponse(
571
570
  context: SdkContext,
572
571
  response: HttpOperationResponse,
@@ -749,6 +748,9 @@ function emitBasicOperation(
749
748
  });
750
749
 
751
750
  for (const param of httpOperation.parameters.parameters) {
751
+ if (isIgnoredHeaderParam(param)) {
752
+ continue;
753
+ }
752
754
  const emittedParam = emitParameter(context, param, "Method");
753
755
  if (isApiVersion(context, param) && apiVersionParam === undefined) {
754
756
  apiVersionParam = emittedParam;
@@ -768,7 +770,7 @@ function emitBasicOperation(
768
770
  innerResponse
769
771
  );
770
772
  if (isErrorModel(context.program, response.type)) {
771
- // * is valid status code in cadl but invalid for autorest.python
773
+ // * is valid status code in typespec but invalid for autorest.python
772
774
  if (response.statusCode === "*") {
773
775
  exceptions.push(emittedResponse);
774
776
  }
@@ -820,7 +822,7 @@ function emitBasicOperation(
820
822
  }
821
823
 
822
824
  function isReadOnly(program: Program, type: ModelProperty): boolean {
823
- // https://microsoft.github.io/cadl/standard-library/rest/operations#automatic-visibility
825
+ // https://microsoft.github.io/typespec/standard-library/http/operations#automatic-visibility
824
826
  // Only "read" should be readOnly
825
827
  const visibility = getVisibility(program, type);
826
828
  if (visibility) {
@@ -834,6 +836,7 @@ function emitProperty(
834
836
  context: SdkContext,
835
837
  property: ModelProperty
836
838
  ): Record<string, any> {
839
+ const newProperty = applyEncoding(context.program, property, property);
837
840
  let clientDefaultValue = undefined;
838
841
  const propertyDefaultKind = property.default?.kind;
839
842
  if (
@@ -845,6 +848,10 @@ function emitProperty(
845
848
  clientDefaultValue = property.default.value;
846
849
  }
847
850
 
851
+ if (propertyDefaultKind === "EnumMember") {
852
+ clientDefaultValue = property.default.value ?? property.default.name;
853
+ }
854
+
848
855
  // const [clientName, jsonName] = getPropertyNames(context, property);
849
856
  const clientName = property.name;
850
857
  const jsonName =
@@ -853,16 +860,18 @@ function emitProperty(
853
860
  if (property.model) {
854
861
  getType(context, property.model);
855
862
  }
863
+ const type = getType(context, property.type);
856
864
  return {
857
865
  clientName: applyCasing(clientName, { casing: CASING }),
858
866
  restApiName: jsonName,
859
- type: getType(context, property.type),
867
+ type: newProperty.format ? { ...type, format: newProperty.format } : type,
860
868
  optional: property.optional,
861
869
  description: getDocStr(context.program, property),
862
870
  addedOn: getAddedOnVersion(context.program, property),
863
871
  readonly:
864
872
  isReadOnly(context.program, property) || isKey(context.program, property),
865
- clientDefaultValue: clientDefaultValue
873
+ clientDefaultValue: clientDefaultValue,
874
+ format: newProperty.format
866
875
  };
867
876
  }
868
877
 
@@ -896,9 +905,35 @@ function emitModel(context: SdkContext, type: Model): Record<string, any> {
896
905
  baseModel = getType(context, type.baseModel);
897
906
  }
898
907
  const effectiveName = getEffectiveSchemaType(context.program, type).name;
899
- const modelName = effectiveName
900
- ? effectiveName
901
- : getName(context.program, type);
908
+ const overridedModelName =
909
+ getProjectedName(context.program, type, "javascript") ??
910
+ getProjectedName(context.program, type, "client") ??
911
+ getFriendlyName(context.program, type);
912
+ let modelName =
913
+ overridedModelName ??
914
+ (effectiveName ? effectiveName : getName(context.program, type));
915
+ if (
916
+ !overridedModelName &&
917
+ type.templateMapper &&
918
+ type.templateMapper.args &&
919
+ type.templateMapper.args.length > 0 &&
920
+ getPagedResult(context.program, type)
921
+ ) {
922
+ modelName =
923
+ type.templateMapper.args
924
+ .map((it) => {
925
+ switch (it.kind) {
926
+ case "Model":
927
+ return it.name;
928
+ case "String":
929
+ return it.value;
930
+ default:
931
+ return "";
932
+ }
933
+ })
934
+ .join("") + "List";
935
+ }
936
+
902
937
  return {
903
938
  type: "model",
904
939
  name: modelName,
@@ -1000,9 +1035,10 @@ function emitStdScalar(
1000
1035
  program: Program,
1001
1036
  scalar: Scalar & { name: IntrinsicScalarName }
1002
1037
  ): Record<string, any> {
1038
+ const newScalar = applyEncoding(program, scalar, scalar);
1003
1039
  switch (scalar.name) {
1004
1040
  case "bytes":
1005
- return { type: "byte-array", format: getEncode(program, scalar) };
1041
+ return { type: "byte-array", format: newScalar.format };
1006
1042
  case "int8":
1007
1043
  case "int16":
1008
1044
  case "int32":
@@ -1024,13 +1060,15 @@ function emitStdScalar(
1024
1060
  case "boolean":
1025
1061
  return { type: "boolean" };
1026
1062
  case "plainDate":
1027
- return { type: "date" };
1063
+ return { type: "datetime", format: newScalar.format ?? "date" };
1028
1064
  case "utcDateTime":
1029
- return { type: "datetime", format: "date-time" };
1065
+ return { type: "datetime", format: newScalar.format };
1030
1066
  case "plainTime":
1031
- return { type: "time" };
1067
+ return { type: "datetime", format: newScalar.format ?? "time" };
1068
+ case "offsetDateTime":
1069
+ return { type: "datetime", format: newScalar.format ?? "rfc7231" };
1032
1070
  case "duration":
1033
- return { type: "duration" };
1071
+ return { type: "duration", format: newScalar.format };
1034
1072
  case "numeric":
1035
1073
  return {}; // Waiting on design for more precise type https://github.com/microsoft/cadl/issues/1260
1036
1074
  default:
@@ -1038,12 +1076,51 @@ function emitStdScalar(
1038
1076
  }
1039
1077
  }
1040
1078
 
1079
+ function applyEncoding(
1080
+ program: Program,
1081
+ typespecType: Scalar | ModelProperty,
1082
+ target: any = {}
1083
+ ) {
1084
+ const encodeData = getEncode(program, typespecType);
1085
+ const formatData = getFormat(program, typespecType);
1086
+ formatData;
1087
+ if (encodeData) {
1088
+ const newTarget = { ...target };
1089
+ const newType = emitScalar(program, encodeData.type);
1090
+ // newTarget["type"] = newType["type"];
1091
+ // If the target already has a format it takes priority. (e.g. int32)
1092
+ newTarget["format"] = mergeFormatAndEncoding(
1093
+ newTarget.format,
1094
+ encodeData.encoding,
1095
+ newType["format"]
1096
+ );
1097
+ return newTarget;
1098
+ }
1099
+ return target;
1100
+ }
1101
+
1102
+ function mergeFormatAndEncoding(
1103
+ format: string | undefined,
1104
+ encoding: string,
1105
+ encodeAsFormat: string | undefined
1106
+ ): string {
1107
+ switch (format) {
1108
+ case undefined:
1109
+ return encodeAsFormat ?? encoding;
1110
+ case "date-time":
1111
+ return encoding;
1112
+ case "duration":
1113
+ default:
1114
+ return encodeAsFormat ?? encoding;
1115
+ }
1116
+ }
1117
+
1041
1118
  function applyIntrinsicDecorators(
1042
1119
  program: Program,
1043
1120
  type: Scalar | ModelProperty,
1044
1121
  result: any
1045
1122
  ): Record<string, any> {
1046
- const newResult = { ...result };
1123
+ let newResult = { ...result };
1047
1124
  const docStr = getDoc(program, type);
1048
1125
  const isString = isStringType(program, getPropertyType(type));
1049
1126
  const isNumeric = isNumericType(program, getPropertyType(type));
@@ -1052,10 +1129,7 @@ function applyIntrinsicDecorators(
1052
1129
  newResult.description = docStr;
1053
1130
  }
1054
1131
 
1055
- const formatStr = getFormat(program, type);
1056
- if (isString && !result.format && formatStr) {
1057
- newResult.format = formatStr;
1058
- }
1132
+ newResult = applyEncoding(program, type, newResult);
1059
1133
 
1060
1134
  const pattern = getPattern(program, type);
1061
1135
  if (isString && !result.pattern && pattern) {
@@ -1096,7 +1170,8 @@ function applyIntrinsicDecorators(
1096
1170
 
1097
1171
  function emitScalar(program: Program, scalar: Scalar): Record<string, any> {
1098
1172
  let result: Record<string, any> = {};
1099
- if (program.checker.isStdType(scalar)) {
1173
+ const isStd = program.checker.isStdType(scalar);
1174
+ if (isStd) {
1100
1175
  result = emitStdScalar(program, scalar);
1101
1176
  } else if (scalar.baseScalar) {
1102
1177
  result = emitScalar(program, scalar.baseScalar);
@@ -1127,7 +1202,7 @@ function emitListOrDict(
1127
1202
  return undefined;
1128
1203
  }
1129
1204
 
1130
- function mapCadlType(context: SdkContext, type: Type): any {
1205
+ function mapTypeSpecType(context: SdkContext, type: Type): any {
1131
1206
  switch (type.kind) {
1132
1207
  case "Number":
1133
1208
  return constantType(type.value, intOrFloat(type.value));
@@ -1228,7 +1303,7 @@ function emitType(context: SdkContext, type: EmitterType): Record<string, any> {
1228
1303
  if (type.kind === "CredentialTypeUnion") {
1229
1304
  return emitCredentialUnion(type);
1230
1305
  }
1231
- const builtinType = mapCadlType(context, type);
1306
+ const builtinType = mapTypeSpecType(context, type);
1232
1307
  if (builtinType !== undefined) {
1233
1308
  // add in description elements for types derived from primitive types (SecureString, etc.)
1234
1309
  const doc = getDoc(context.program, type);
@@ -1288,9 +1363,38 @@ function emitOperationGroups(
1288
1363
  operations: clientOperations
1289
1364
  });
1290
1365
  }
1366
+ resolveConflictIfExist(operationGroups);
1291
1367
  return operationGroups;
1292
1368
  }
1293
1369
 
1370
+ function resolveConflictIfExist(operationGroups: OperationGroup[]) {
1371
+ if (operationGroups.length < 2) {
1372
+ return;
1373
+ }
1374
+
1375
+ const nameSet = new Set<string>();
1376
+ const hasConflict = operationGroups.some((g) =>
1377
+ g.operations.some((op) => {
1378
+ if (nameSet.has(op.name)) {
1379
+ return true;
1380
+ } else {
1381
+ nameSet.add(op.name);
1382
+ return false;
1383
+ }
1384
+ })
1385
+ );
1386
+ if (!hasConflict) {
1387
+ return;
1388
+ }
1389
+ // Append operation group prefix
1390
+ operationGroups.forEach((g) =>
1391
+ g.operations.forEach((op) => {
1392
+ op.oriName = op.name;
1393
+ op.name = `${g.propertyName}_${op.name}`;
1394
+ })
1395
+ );
1396
+ }
1397
+
1294
1398
  function getServerHelper(
1295
1399
  program: Program,
1296
1400
  namespace: Namespace
@@ -1468,7 +1572,8 @@ function emitClients(
1468
1572
  operationGroups: emitOperationGroups(context, client, rlcModels),
1469
1573
  url: server ? server.url : "",
1470
1574
  apiVersions: [],
1471
- rlcClientName: rlcModels ? getClientName(rlcModels) : client.name
1575
+ rlcClientName: rlcModels ? getClientName(rlcModels) : client.name,
1576
+ subfolder: ""
1472
1577
  };
1473
1578
  const emittedApiVersionParam = getApiVersionParameter(context);
1474
1579
  if (emittedApiVersionParam) {
@@ -1501,23 +1606,28 @@ function getNamespaces(context: SdkContext): Set<string> {
1501
1606
  }
1502
1607
 
1503
1608
  export function emitCodeModel(
1504
- context: EmitContext<EmitterOptions>,
1609
+ dpgContext: SdkContext,
1505
1610
  rlcModelsMap: Map<string, RLCModel>,
1611
+ modularSourcesRoot: string,
1612
+ project: Project,
1506
1613
  options: { casing: "snake" | "camel" } = { casing: "snake" }
1507
1614
  ): ModularCodeModel {
1508
1615
  CASING = options.casing ?? CASING;
1509
- const dpgContext = createSdkContext(context);
1510
1616
  const clientNamespaceString =
1511
1617
  getClientNamespaceString(dpgContext)?.toLowerCase();
1512
1618
  // Get types
1513
1619
  const codeModel: ModularCodeModel = {
1514
- options: transformRLCOptions(context.options as any, dpgContext),
1620
+ options: dpgContext.rlcOptions ?? {},
1621
+ modularOptions: { sourceRoot: modularSourcesRoot },
1515
1622
  namespace: clientNamespaceString,
1516
1623
  subnamespaceToClients: {},
1517
1624
  clients: [],
1518
- types: []
1625
+ types: [],
1626
+ project
1519
1627
  };
1520
1628
 
1629
+ typesMap.clear();
1630
+ simpleTypesMap.clear();
1521
1631
  const allModels = getAllModels(dpgContext);
1522
1632
  for (const model of allModels) {
1523
1633
  getType(dpgContext, model);
@@ -1526,12 +1636,25 @@ export function emitCodeModel(
1526
1636
  for (const namespace of getNamespaces(dpgContext)) {
1527
1637
  if (namespace === clientNamespaceString) {
1528
1638
  codeModel.clients = emitClients(dpgContext, namespace, rlcModelsMap);
1639
+ codeModel.clients.length > 1 &&
1640
+ codeModel.clients.map((client) => {
1641
+ client["subfolder"] = normalizeName(
1642
+ client.name.replace("Client", ""),
1643
+ NameType.File
1644
+ );
1645
+ });
1529
1646
  } else {
1530
1647
  codeModel["subnamespaceToClients"][namespace] = emitClients(
1531
1648
  dpgContext,
1532
1649
  namespace,
1533
1650
  rlcModelsMap
1534
1651
  );
1652
+ codeModel["subnamespaceToClients"][namespace].length > 1 &&
1653
+ (codeModel["subnamespaceToClients"][namespace] as HrlcClient[]).map(
1654
+ (client) => {
1655
+ client["subfolder"] = normalizeName(client.name, NameType.File);
1656
+ }
1657
+ );
1535
1658
  }
1536
1659
  }
1537
1660
 
@@ -7,7 +7,7 @@ import {
7
7
  getDeserializePrivateFunction,
8
8
  getOperationOptionsName
9
9
  } from "./helpers/operationHelpers.js";
10
- import { Client, Operation } from "./modularCodeModel.js";
10
+ import { Client, ModularCodeModel, Operation } from "./modularCodeModel.js";
11
11
  import { isRLCMultiEndpoint } from "../utils/clientUtils.js";
12
12
  import { getDocsFromDescription } from "./helpers/docsHelpers.js";
13
13
  import { SdkContext } from "../utils/interfaces.js";
@@ -19,12 +19,11 @@ import { SdkContext } from "../utils/interfaces.js";
19
19
  */
20
20
  export function buildOperationFiles(
21
21
  dpgContext: SdkContext,
22
+ codeModel: ModularCodeModel,
22
23
  client: Client,
23
- project: Project,
24
- srcPath: string = "src",
25
- subfolder: string = "",
26
24
  needUnexpectedHelper: boolean = true
27
25
  ) {
26
+ const operationFiles = [];
28
27
  for (const operationGroup of client.operationGroups) {
29
28
  const importSet: Map<string, Set<string>> = new Map<string, Set<string>>();
30
29
  const fileName = operationGroup.className
@@ -33,7 +32,9 @@ export function buildOperationFiles(
33
32
  // into a nameless operation group. We'll call this operations.
34
33
  "operations";
35
34
 
36
- const operationGroupFile = project.createSourceFile(
35
+ const subfolder = client.subfolder;
36
+ const srcPath = codeModel.modularOptions.sourceRoot;
37
+ const operationGroupFile = codeModel.project.createSourceFile(
37
38
  `${srcPath}/${
38
39
  subfolder && subfolder !== "" ? subfolder + "/" : ""
39
40
  }api/${fileName}.ts`
@@ -41,7 +42,7 @@ export function buildOperationFiles(
41
42
 
42
43
  // Import models used from ./models.ts
43
44
  // We SHOULD keep this because otherwise ts-morph will "helpfully" try to import models from the rest layer when we call fixMissingImports().
44
- importModels(srcPath, operationGroupFile, project, subfolder);
45
+ importModels(srcPath, operationGroupFile, codeModel.project, subfolder);
45
46
 
46
47
  const namedImports: string[] = [];
47
48
  let clientType = "Client";
@@ -114,7 +115,9 @@ export function buildOperationFiles(
114
115
  operationGroupFile.fixMissingImports();
115
116
  // have to fixUnusedIdentifiers after everything get generated.
116
117
  operationGroupFile.fixUnusedIdentifiers();
118
+ operationFiles.push(operationGroupFile);
117
119
  }
120
+ return operationFiles;
118
121
  }
119
122
 
120
123
  export function importModels(
@@ -134,10 +137,12 @@ export function importModels(
134
137
  models.push(entry[0]);
135
138
  }
136
139
 
137
- sourceFile.addImportDeclaration({
138
- moduleSpecifier: "../models/models.js",
139
- namedImports: models
140
- });
140
+ if (models.length > 0) {
141
+ sourceFile.addImportDeclaration({
142
+ moduleSpecifier: "../models/models.js",
143
+ namedImports: models
144
+ });
145
+ }
141
146
 
142
147
  // Import all models and then let ts-morph clean up the unused ones
143
148
  // we can't fixUnusedIdentifiers here because the operaiton files are still being generated.
@@ -169,7 +174,7 @@ export function buildOperationOptions(
169
174
  return {
170
175
  docs: getDocsFromDescription(p.description),
171
176
  hasQuestionToken: true,
172
- ...buildType(p.clientName, p.type)
177
+ ...buildType(p.clientName, p.type, p.format)
173
178
  };
174
179
  })
175
180
  });
@@ -100,7 +100,7 @@ export function emitPackage(
100
100
  generateSample
101
101
  )}`,
102
102
  clean:
103
- "rimraf dist dist-browser dist-esm test-dist temp types *.tgz *.log",
103
+ "rimraf --glob dist dist-browser dist-esm test-dist temp types *.tgz *.log",
104
104
  "execute:samples": "echo skipped",
105
105
  "extract-api":
106
106
  "rimraf review && mkdirp ./review && api-extractor run --local",
@@ -156,7 +156,7 @@ export function emitPackage(
156
156
  eslint: "^8.0.0",
157
157
  mkdirp: "^2.1.2",
158
158
  prettier: "^2.5.1",
159
- rimraf: "^3.0.0",
159
+ rimraf: "^5.0.0",
160
160
  "source-map-support": "^0.5.9",
161
161
  typescript: "~5.0.0"
162
162
  }
@@ -1,14 +1,15 @@
1
1
  import { Project, SourceFile } from "ts-morph";
2
2
  import { getClientName } from "./helpers/namingHelpers.js";
3
- import { Client } from "./modularCodeModel.js";
3
+ import { Client, ModularCodeModel } from "./modularCodeModel.js";
4
4
 
5
5
  export function buildRootIndex(
6
+ codeModel: ModularCodeModel,
6
7
  client: Client,
7
- project: Project,
8
- rootIndexFile: SourceFile,
9
- srcPath: string,
10
- subfolder: string
8
+ rootIndexFile: SourceFile
11
9
  ) {
10
+ const { project } = codeModel;
11
+ const srcPath = codeModel.modularOptions.sourceRoot;
12
+ const subfolder = client.subfolder ?? "";
12
13
  const clientName = `${getClientName(client)}Client`;
13
14
  const clientFile = project.getSourceFile(
14
15
  `${srcPath}/${subfolder !== "" ? subfolder + "/" : ""}${clientName}.ts`
@@ -71,12 +72,12 @@ function exportModels(
71
72
  }
72
73
 
73
74
  export function buildSubClientIndexFile(
74
- client: Client,
75
- project: Project,
76
- srcPath: string,
77
- subfolder: string
75
+ codeModel: ModularCodeModel,
76
+ client: Client
78
77
  ) {
79
- const subClientIndexFile = project.createSourceFile(
78
+ const subfolder = client.subfolder ?? "";
79
+ const srcPath = codeModel.modularOptions.sourceRoot;
80
+ const subClientIndexFile = codeModel.project.createSourceFile(
80
81
  `${srcPath}/${subfolder !== "" ? subfolder + "/" : ""}index.ts`,
81
82
  undefined,
82
83
  { overwrite: true }
@@ -85,12 +86,18 @@ export function buildSubClientIndexFile(
85
86
  const clientFilePath = `${srcPath}/${
86
87
  subfolder !== "" ? subfolder + "/" : ""
87
88
  }${clientName}.ts`;
88
- const clientFile = project.getSourceFile(clientFilePath);
89
+ const clientFile = codeModel.project.getSourceFile(clientFilePath);
89
90
 
90
91
  if (!clientFile) {
91
92
  throw new Error(`Couldn't find client file: ${clientFilePath}`);
92
93
  }
93
94
 
94
95
  exportClassicalClient(client, subClientIndexFile, subfolder, true);
95
- exportModels(subClientIndexFile, project, srcPath, clientName, subfolder);
96
+ exportModels(
97
+ subClientIndexFile,
98
+ codeModel.project,
99
+ srcPath,
100
+ clientName,
101
+ subfolder
102
+ );
96
103
  }