@azure-tools/typespec-ts 0.19.0 → 0.20.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 (93) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +8 -4
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/lib.d.ts +28 -1
  6. package/dist/src/lib.d.ts.map +1 -1
  7. package/dist/src/lib.js +18 -0
  8. package/dist/src/lib.js.map +1 -1
  9. package/dist/src/modular/buildClassicalClient.js +9 -0
  10. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  11. package/dist/src/modular/buildClassicalOperationGroups.d.ts.map +1 -1
  12. package/dist/src/modular/buildClassicalOperationGroups.js +5 -1
  13. package/dist/src/modular/buildClassicalOperationGroups.js.map +1 -1
  14. package/dist/src/modular/buildCodeModel.d.ts.map +1 -1
  15. package/dist/src/modular/buildCodeModel.js +81 -65
  16. package/dist/src/modular/buildCodeModel.js.map +1 -1
  17. package/dist/src/modular/buildOperations.d.ts +1 -0
  18. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  19. package/dist/src/modular/buildOperations.js +30 -13
  20. package/dist/src/modular/buildOperations.js.map +1 -1
  21. package/dist/src/modular/buildPagingFiles.d.ts +4 -0
  22. package/dist/src/modular/buildPagingFiles.d.ts.map +1 -0
  23. package/dist/src/modular/buildPagingFiles.js +333 -0
  24. package/dist/src/modular/buildPagingFiles.js.map +1 -0
  25. package/dist/src/modular/buildProjectFiles.d.ts.map +1 -1
  26. package/dist/src/modular/buildProjectFiles.js +15 -8
  27. package/dist/src/modular/buildProjectFiles.js.map +1 -1
  28. package/dist/src/modular/buildSubpathIndex.d.ts.map +1 -1
  29. package/dist/src/modular/buildSubpathIndex.js +10 -1
  30. package/dist/src/modular/buildSubpathIndex.js.map +1 -1
  31. package/dist/src/modular/emitModels.d.ts +21 -2
  32. package/dist/src/modular/emitModels.d.ts.map +1 -1
  33. package/dist/src/modular/emitModels.js +26 -5
  34. package/dist/src/modular/emitModels.js.map +1 -1
  35. package/dist/src/modular/helpers/operationHelpers.d.ts +7 -4
  36. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  37. package/dist/src/modular/helpers/operationHelpers.js +135 -99
  38. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  39. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  40. package/dist/src/modular/helpers/typeHelpers.js +2 -1
  41. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  42. package/dist/src/modular/modularCodeModel.d.ts +2 -1
  43. package/dist/src/modular/modularCodeModel.d.ts.map +1 -1
  44. package/dist/src/transform/transformApiVersionInfo.d.ts.map +1 -1
  45. package/dist/src/transform/transformApiVersionInfo.js +16 -10
  46. package/dist/src/transform/transformApiVersionInfo.js.map +1 -1
  47. package/dist/src/transform/transformHelperFunctionDetails.d.ts +1 -1
  48. package/dist/src/transform/transformHelperFunctionDetails.d.ts.map +1 -1
  49. package/dist/src/transform/transformHelperFunctionDetails.js +11 -16
  50. package/dist/src/transform/transformHelperFunctionDetails.js.map +1 -1
  51. package/dist/src/transform/transformParameters.d.ts.map +1 -1
  52. package/dist/src/transform/transformParameters.js +19 -14
  53. package/dist/src/transform/transformParameters.js.map +1 -1
  54. package/dist/src/transform/transformResponses.js +5 -3
  55. package/dist/src/transform/transformResponses.js.map +1 -1
  56. package/dist/src/transform/transformSchemas.d.ts.map +1 -1
  57. package/dist/src/transform/transformSchemas.js +32 -17
  58. package/dist/src/transform/transformSchemas.js.map +1 -1
  59. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  60. package/dist/src/utils/emitUtil.js +1 -1
  61. package/dist/src/utils/emitUtil.js.map +1 -1
  62. package/dist/src/utils/modelUtils.d.ts +1 -0
  63. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  64. package/dist/src/utils/modelUtils.js +103 -57
  65. package/dist/src/utils/modelUtils.js.map +1 -1
  66. package/dist/src/utils/operationUtil.d.ts +3 -1
  67. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  68. package/dist/src/utils/operationUtil.js +21 -7
  69. package/dist/src/utils/operationUtil.js.map +1 -1
  70. package/dist/tsconfig.tsbuildinfo +1 -1
  71. package/package.json +18 -19
  72. package/src/index.ts +20 -4
  73. package/src/lib.ts +18 -0
  74. package/src/modular/buildClassicalClient.ts +15 -0
  75. package/src/modular/buildClassicalOperationGroups.ts +17 -1
  76. package/src/modular/buildCodeModel.ts +100 -77
  77. package/src/modular/buildOperations.ts +55 -13
  78. package/src/modular/buildPagingFiles.ts +356 -0
  79. package/src/modular/buildProjectFiles.ts +17 -15
  80. package/src/modular/buildSubpathIndex.ts +12 -1
  81. package/src/modular/emitModels.ts +29 -5
  82. package/src/modular/helpers/operationHelpers.ts +130 -119
  83. package/src/modular/helpers/typeHelpers.ts +8 -6
  84. package/src/modular/modularCodeModel.ts +2 -1
  85. package/src/transform/transformApiVersionInfo.ts +25 -15
  86. package/src/transform/transformHelperFunctionDetails.ts +19 -21
  87. package/src/transform/transformParameters.ts +33 -14
  88. package/src/transform/transformResponses.ts +8 -3
  89. package/src/transform/transformSchemas.ts +33 -17
  90. package/src/transform/transfromRLCOptions.ts +2 -2
  91. package/src/utils/emitUtil.ts +1 -1
  92. package/src/utils/modelUtils.ts +119 -63
  93. package/src/utils/operationUtil.ts +26 -10
@@ -55,13 +55,14 @@ import {
55
55
  Schema,
56
56
  SchemaContext
57
57
  } from "@azure-tools/rlc-common";
58
- import { getResourceOperation } from "@typespec/rest";
59
58
  import {
60
59
  getHeaderFieldName,
61
60
  getPathParamName,
62
61
  getQueryParamName,
63
62
  isStatusCode,
64
- HttpOperation
63
+ HttpOperation,
64
+ createMetadataInfo,
65
+ Visibility
65
66
  } from "@typespec/http";
66
67
  import { getPagedResult, isFixed } from "@azure-tools/typespec-azure-core";
67
68
  import { extractPagedMetadataNested } from "./operationUtil.js";
@@ -190,7 +191,7 @@ export function getSchemaForType(
190
191
  } else if (type.kind === "UnionVariant") {
191
192
  return getSchemaForUnionVariant(dpgContext, type, usage);
192
193
  } else if (type.kind === "Enum") {
193
- return getSchemaForEnum(program, type);
194
+ return getSchemaForEnum(dpgContext, type);
194
195
  } else if (type.kind === "Scalar") {
195
196
  return getSchemaForScalar(dpgContext, type, relevantProperty);
196
197
  } else if (type.kind === "EnumMember") {
@@ -634,9 +635,9 @@ function getSchemaForModel(
634
635
  modelSchema.discriminator = {
635
636
  name: propertyName,
636
637
  type: "string",
637
- required: true,
638
638
  description: `Discriminator property for ${model.name}.`
639
639
  };
640
+ modelSchema.discriminatorValue = propertyName;
640
641
 
641
642
  modelSchema.isPolyParent = true;
642
643
  }
@@ -678,15 +679,18 @@ function getSchemaForModel(
678
679
  propSchema
679
680
  );
680
681
  propSchema.usage = usage;
681
- // Use the description from ModelProperty not devired from Model Type
682
+ // Use the description from ModelProperty not derived from Model Type
682
683
  propSchema.description = propertyDescription;
683
684
  modelSchema.properties[name] = propSchema;
684
685
  // if this property is a discriminator property, remove it to keep autorest validation happy
685
- if (model.baseModel) {
686
- const { propertyName } = getDiscriminator(program, model.baseModel) || {};
687
- if (propertyName && name === `"${propertyName}"`) {
688
- continue;
689
- }
686
+ const { propertyName } = getDiscriminator(program, model) || {};
687
+ if (
688
+ propertyName &&
689
+ name === `"${propertyName}"` &&
690
+ modelSchema.discriminator
691
+ ) {
692
+ modelSchema.discriminator.type = propSchema.typeName ?? propSchema.type;
693
+ continue;
690
694
  }
691
695
 
692
696
  // Apply decorators on the property to the type's schema
@@ -815,26 +819,28 @@ function getSchemaForEnumMember(program: Program, e: EnumMember) {
815
819
  return { type, description: getDoc(program, e), isConstant: true };
816
820
  }
817
821
 
818
- function getSchemaForEnum(program: Program, e: Enum) {
822
+ function getSchemaForEnum(dpgContext: SdkContext, e: Enum) {
819
823
  const values = [];
820
824
  const type = enumMemberType(e.members.values().next().value);
821
825
  for (const option of e.members.values()) {
822
826
  if (type !== enumMemberType(option)) {
823
- reportDiagnostic(program, { code: "union-unsupported", target: e });
827
+ reportDiagnostic(dpgContext.program, {
828
+ code: "union-unsupported",
829
+ target: e
830
+ });
824
831
  continue;
825
832
  }
826
833
 
827
- values.push(option.value ?? option.name);
834
+ values.push(getSchemaForType(dpgContext, option));
828
835
  }
829
836
 
830
- const schema: any = { type, description: getDoc(program, e) };
837
+ const schema: any = { type, description: getDoc(dpgContext.program, e) };
831
838
  if (values.length > 0) {
832
839
  schema.enum = values;
833
- schema.type =
834
- type === "string"
835
- ? values.map((item) => `"${item}"`).join("|")
836
- : values.map((item) => `${item}`).join("|");
837
- if (!isFixed(program, e)) {
840
+ schema.type = values
841
+ .map((item) => `${getTypeName(item, [SchemaContext.Input]) ?? item}`)
842
+ .join(" | ");
843
+ if (!isFixed(dpgContext.program, e)) {
838
844
  schema.name = "string";
839
845
  schema.typeName = "string";
840
846
  }
@@ -1048,7 +1054,7 @@ function getSchemaForStdScalar(
1048
1054
  case "safeint":
1049
1055
  return applyIntrinsicDecorators(program, type, {
1050
1056
  type: "number",
1051
- format: "int64"
1057
+ format: "safeint"
1052
1058
  });
1053
1059
  case "uint8":
1054
1060
  return applyIntrinsicDecorators(program, type, {
@@ -1073,18 +1079,44 @@ function getSchemaForStdScalar(
1073
1079
  case "float64":
1074
1080
  return applyIntrinsicDecorators(program, type, {
1075
1081
  type: "number",
1076
- format: "double"
1082
+ format: "float64"
1077
1083
  });
1078
1084
  case "float32":
1079
1085
  return applyIntrinsicDecorators(program, type, {
1080
1086
  type: "number",
1081
- format: "float"
1087
+ format: "float32"
1082
1088
  });
1083
1089
  case "float":
1084
1090
  return applyIntrinsicDecorators(program, type, {
1085
1091
  type: "number",
1086
1092
  format: "float"
1087
1093
  });
1094
+ case "decimal":
1095
+ reportDiagnostic(program, {
1096
+ code: "decimal-to-number",
1097
+ format: {
1098
+ propertyName: relevantProperty?.name ?? ""
1099
+ },
1100
+ target: relevantProperty ?? type
1101
+ });
1102
+ return applyIntrinsicDecorators(program, type, {
1103
+ type: "number",
1104
+ format: "decimal",
1105
+ description: "decimal"
1106
+ });
1107
+ case "decimal128":
1108
+ reportDiagnostic(program, {
1109
+ code: "decimal-to-number",
1110
+ format: {
1111
+ propertyName: relevantProperty?.name ?? ""
1112
+ },
1113
+ target: relevantProperty ?? type
1114
+ });
1115
+ return applyIntrinsicDecorators(program, type, {
1116
+ type: "number",
1117
+ format: "decimal128",
1118
+ description: "decimal128"
1119
+ });
1088
1120
  case "string":
1089
1121
  if (format === "binary") {
1090
1122
  return {
@@ -1167,6 +1199,37 @@ export function getTypeName(schema: Schema, usage?: SchemaContext[]): string {
1167
1199
  return getPriorityName(schema, usage) ?? schema.type ?? "any";
1168
1200
  }
1169
1201
 
1202
+ export function getSerializeTypeName(
1203
+ program: Program,
1204
+ schema: Schema,
1205
+ usage?: SchemaContext[]
1206
+ ): string {
1207
+ const typeName = getTypeName(schema, usage);
1208
+ const formattedName = (schema.alias ?? typeName).replace(
1209
+ "Date | string",
1210
+ "string"
1211
+ );
1212
+ const canSerialize = schema.enum
1213
+ ? schema.enum.every((type) => {
1214
+ return isSerializable(type) || type.type === "null";
1215
+ })
1216
+ : isSerializable(schema);
1217
+ if (canSerialize) {
1218
+ return schema.alias ? typeName : formattedName;
1219
+ }
1220
+ reportDiagnostic(program, {
1221
+ code: "unable-serialized-type",
1222
+ format: { type: typeName },
1223
+ target: NoTarget
1224
+ });
1225
+ return "string";
1226
+ function isSerializable(type: any) {
1227
+ return (
1228
+ ["string", "number", "boolean"].includes(type.type) || type.isConstant
1229
+ );
1230
+ }
1231
+ }
1232
+
1170
1233
  export function getImportedModelName(
1171
1234
  schema: Schema,
1172
1235
  usage?: SchemaContext[]
@@ -1234,7 +1297,26 @@ function getPriorityName(schema: Schema, usage?: SchemaContext[]): string {
1234
1297
 
1235
1298
  function getEnumStringDescription(type: any) {
1236
1299
  if (type.name === "string" && type.enum && type.enum.length > 0) {
1237
- return `Possible values: ${type.enum.join(", ")}`;
1300
+ return `Possible values: ${type.enum
1301
+ .map((e: Schema) => {
1302
+ return e.type;
1303
+ })
1304
+ .join(", ")}`;
1305
+ }
1306
+ return undefined;
1307
+ }
1308
+
1309
+ function getDecimalDescription(type: any) {
1310
+ if (
1311
+ (type.format === "decimal" || type.format === "decimal128") &&
1312
+ type.type === "number"
1313
+ ) {
1314
+ return `NOTE: This property is represented as a 'number' in JavaScript, but it corresponds to a 'decimal' type in other languages.
1315
+ Due to the inherent limitations of floating-point arithmetic in JavaScript, precision issues may arise when performing arithmetic operations.
1316
+ If your application requires high precision for arithmetic operations or when round-tripping data back to other languages, consider using a library like decimal.js, which provides an arbitrary-precision Decimal type.
1317
+ For simpler cases, where you need to control the number of decimal places for display purposes, you can use the 'toFixed()' method. However, be aware that 'toFixed()' returns a string and may not be suitable for all arithmetic precision requirements.
1318
+ Always be cautious with direct arithmetic operations and consider implementing appropriate rounding strategies to maintain accuracy.
1319
+ `;
1238
1320
  }
1239
1321
  return undefined;
1240
1322
  }
@@ -1246,7 +1328,8 @@ export function getFormattedPropertyDoc(
1246
1328
  sperator: string = "\n\n"
1247
1329
  ) {
1248
1330
  const propertyDoc = getDoc(program, type);
1249
- const enhancedDocFromType = getEnumStringDescription(schemaType);
1331
+ const enhancedDocFromType =
1332
+ getEnumStringDescription(schemaType) ?? getDecimalDescription(schemaType);
1250
1333
  if (propertyDoc && enhancedDocFromType) {
1251
1334
  return `${propertyDoc}${sperator}${enhancedDocFromType}`;
1252
1335
  }
@@ -1257,41 +1340,14 @@ export function getBodyType(
1257
1340
  program: Program,
1258
1341
  route: HttpOperation
1259
1342
  ): Type | undefined {
1260
- let bodyModel = route.parameters.bodyType;
1261
- if (bodyModel && bodyModel.kind === "Model" && route.operation) {
1262
- const resourceType = getResourceOperation(
1263
- program,
1264
- route.operation
1265
- )?.resourceType;
1266
- if (resourceType && route.responses && route.responses.length > 0) {
1267
- const resp = route.responses[0];
1268
- if (resp && resp.responses && resp.responses.length > 0) {
1269
- const responseBody = resp.responses[0]?.body;
1270
- if (responseBody) {
1271
- const bodyTypeInResponse = getEffectiveModelFromType(
1272
- program,
1273
-
1274
- responseBody.type
1275
- );
1276
- // response body type is reosurce type, and request body type (if templated) contains resource type
1277
- if (
1278
- bodyTypeInResponse === resourceType &&
1279
- bodyModel.templateMapper &&
1280
- bodyModel.templateMapper.args &&
1281
- bodyModel.templateMapper.args.some((it) => {
1282
- return it.kind === "Model" || it.kind === "Union"
1283
- ? it === bodyTypeInResponse
1284
- : false;
1285
- })
1286
- ) {
1287
- bodyModel = resourceType;
1288
- }
1289
- }
1290
- }
1291
- }
1292
- if (resourceType && bodyModel.name === "") {
1293
- bodyModel = resourceType;
1294
- }
1343
+ const bodyModel = route.parameters.body?.type;
1344
+ if (bodyModel) {
1345
+ const metadataInfo = createMetadataInfo(program);
1346
+ const payloadType = metadataInfo.getEffectivePayloadType(
1347
+ bodyModel,
1348
+ Visibility.All
1349
+ );
1350
+ return payloadType;
1295
1351
  }
1296
1352
  return bodyModel;
1297
1353
  }
@@ -1444,7 +1500,7 @@ export function getModelInlineSigniture(
1444
1500
  schema: ObjectSchema,
1445
1501
  options: { importedModels?: Set<string>; usage?: SchemaContext[] } = {}
1446
1502
  ) {
1447
- let schemaSigiture = `{`;
1503
+ let schemaSignature = `{`;
1448
1504
  for (const propName in schema.properties) {
1449
1505
  const propType = schema.properties[propName]!;
1450
1506
  const propTypeName = getTypeName(propType, options.usage);
@@ -1461,9 +1517,9 @@ export function getModelInlineSigniture(
1461
1517
  }
1462
1518
  }
1463
1519
  const isOptional = propType.required ? "" : "?";
1464
- schemaSigiture += `${propName}${isOptional}: ${propTypeName};`;
1520
+ schemaSignature += `${propName}${isOptional}: ${propTypeName};`;
1465
1521
  }
1466
1522
 
1467
- schemaSigiture += `}`;
1468
- return schemaSigiture;
1523
+ schemaSignature += `}`;
1524
+ return schemaSignature;
1469
1525
  }
@@ -179,17 +179,22 @@ export function isDefinedStatusCode(statusCodes: HttpStatusCodesEntry) {
179
179
  export function isBinaryPayload(
180
180
  dpgContext: SdkContext,
181
181
  body: Type,
182
- contentType: string
182
+ contentType: string | string[]
183
183
  ) {
184
- contentType = `"${contentType}"`;
185
- if (
186
- contentType !== `"application/json"` &&
187
- contentType !== `"text/plain"` &&
188
- contentType !== `"application/json" | "text/plain"` &&
189
- contentType !== `"text/plain" | "application/json"` &&
190
- isByteOrByteUnion(dpgContext, body)
191
- ) {
192
- return true;
184
+ const allContentTypes = Array.isArray(contentType)
185
+ ? contentType
186
+ : [contentType];
187
+ for (const type of allContentTypes) {
188
+ const contentType = `"${type}"`;
189
+ if (
190
+ contentType !== `"application/json"` &&
191
+ contentType !== `"text/plain"` &&
192
+ contentType !== `"application/json" | "text/plain"` &&
193
+ contentType !== `"text/plain" | "application/json"` &&
194
+ isByteOrByteUnion(dpgContext, body)
195
+ ) {
196
+ return true;
197
+ }
193
198
  }
194
199
  return false;
195
200
  }
@@ -530,3 +535,14 @@ export function isIgnoredHeaderParam(param: HttpOperationParameter) {
530
535
  ))
531
536
  );
532
537
  }
538
+
539
+ export function parseNextLinkName(
540
+ paged: PagedResultMetadata
541
+ ): string | undefined {
542
+ return paged.nextLinkProperty?.name;
543
+ }
544
+
545
+ export function parseItemName(paged: PagedResultMetadata): string | undefined {
546
+ // TODO: support the nested item names
547
+ return (paged.itemsSegments ?? [])[0];
548
+ }