@azure-tools/typespec-ts 0.44.0 → 0.44.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 (38) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +6 -0
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/modular/emitModels.d.ts.map +1 -1
  6. package/dist/src/modular/emitModels.js +22 -7
  7. package/dist/src/modular/emitModels.js.map +1 -1
  8. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  9. package/dist/src/modular/helpers/operationHelpers.js +13 -9
  10. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  11. package/dist/src/modular/helpers/typeHelpers.d.ts +2 -1
  12. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  13. package/dist/src/modular/helpers/typeHelpers.js +7 -0
  14. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  15. package/dist/src/modular/serialization/buildDeserializerFunction.d.ts.map +1 -1
  16. package/dist/src/modular/serialization/buildDeserializerFunction.js +8 -6
  17. package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
  18. package/dist/src/modular/serialization/buildSerializerFunction.d.ts.map +1 -1
  19. package/dist/src/modular/serialization/buildSerializerFunction.js +8 -6
  20. package/dist/src/modular/serialization/buildSerializerFunction.js.map +1 -1
  21. package/dist/src/modular/serialization/serializeUtils.d.ts +8 -1
  22. package/dist/src/modular/serialization/serializeUtils.d.ts.map +1 -1
  23. package/dist/src/modular/serialization/serializeUtils.js +33 -0
  24. package/dist/src/modular/serialization/serializeUtils.js.map +1 -1
  25. package/dist/src/utils/crossLanguageDef.d.ts +6 -0
  26. package/dist/src/utils/crossLanguageDef.d.ts.map +1 -0
  27. package/dist/src/utils/crossLanguageDef.js +57 -0
  28. package/dist/src/utils/crossLanguageDef.js.map +1 -0
  29. package/dist/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +4 -4
  31. package/src/index.ts +11 -0
  32. package/src/modular/emitModels.ts +26 -9
  33. package/src/modular/helpers/operationHelpers.ts +15 -9
  34. package/src/modular/helpers/typeHelpers.ts +11 -0
  35. package/src/modular/serialization/buildDeserializerFunction.ts +14 -5
  36. package/src/modular/serialization/buildSerializerFunction.ts +14 -5
  37. package/src/modular/serialization/serializeUtils.ts +40 -0
  38. package/src/utils/crossLanguageDef.ts +77 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.44.0",
3
+ "version": "0.44.1",
4
4
  "description": "An experimental TypeSpec emitter for TypeScript RLC",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -26,7 +26,7 @@
26
26
  "@azure-tools/typespec-autorest": "^0.60.0",
27
27
  "@azure-tools/typespec-azure-core": "^0.60.0",
28
28
  "@azure-tools/typespec-azure-resource-manager": "^0.60.0",
29
- "@azure-tools/typespec-client-generator-core": "^0.60.0",
29
+ "@azure-tools/typespec-client-generator-core": "^0.60.3",
30
30
  "@azure/abort-controller": "^2.1.2",
31
31
  "@azure/core-auth": "^1.6.0",
32
32
  "@azure/core-lro": "^3.1.0",
@@ -69,7 +69,7 @@
69
69
  },
70
70
  "peerDependencies": {
71
71
  "@azure-tools/typespec-azure-core": "^0.60.0",
72
- "@azure-tools/typespec-client-generator-core": "^0.60.0",
72
+ "@azure-tools/typespec-client-generator-core": "^0.60.3",
73
73
  "@typespec/compiler": "^1.4.0",
74
74
  "@typespec/http": "^1.4.0",
75
75
  "@typespec/rest": "^0.74.0",
@@ -77,7 +77,7 @@
77
77
  "@typespec/xml": "^0.74.0"
78
78
  },
79
79
  "dependencies": {
80
- "@azure-tools/rlc-common": "^0.44.0",
80
+ "@azure-tools/rlc-common": "^0.44.1",
81
81
  "fs-extra": "^11.1.0",
82
82
  "lodash": "^4.17.21",
83
83
  "prettier": "^3.3.3",
package/src/index.ts CHANGED
@@ -93,6 +93,7 @@ import { provideSdkTypes } from "./framework/hooks/sdkTypes.js";
93
93
  import { transformRLCModel } from "./transform/transform.js";
94
94
  import { transformRLCOptions } from "./transform/transfromRLCOptions.js";
95
95
  import { emitSamples } from "./modular/emitSamples.js";
96
+ import { generateCrossLanguageDefinitionFile } from "./utils/crossLanguageDef.js";
96
97
 
97
98
  export * from "./lib.js";
98
99
 
@@ -374,9 +375,14 @@ export async function $onEmit(context: EmitContext) {
374
375
  console.timeEnd("onEmit: generate files");
375
376
  console.timeEnd("onEmit: generate modular sources");
376
377
  }
378
+
377
379
  interface Metadata {
378
380
  apiVersion?: string;
379
381
  emitterVersion?: string;
382
+ crossLanguageDefinitions?: {
383
+ CrossLanguagePackageId: string;
384
+ CrossLanguageDefinitionId: Record<string, string>;
385
+ };
380
386
  }
381
387
 
382
388
  function buildMetadataJson() {
@@ -392,11 +398,16 @@ export async function $onEmit(context: EmitContext) {
392
398
  if (emitterVersion !== undefined) {
393
399
  content.emitterVersion = emitterVersion;
394
400
  }
401
+ if (dpgContext.rlcOptions?.isModularLibrary) {
402
+ content.crossLanguageDefinitions =
403
+ generateCrossLanguageDefinitionFile(dpgContext);
404
+ }
395
405
  return {
396
406
  path: "metadata.json",
397
407
  content: JSON.stringify(content, null, 2)
398
408
  };
399
409
  }
410
+
400
411
  async function generateMetadataAndTest(context: SdkContext) {
401
412
  const project = useContext("outputProject");
402
413
  if (rlcCodeModels.length === 0 || !rlcCodeModels[0]) {
@@ -51,7 +51,10 @@ import {
51
51
  isAzureCoreLroType
52
52
  } from "../utils/modelUtils.js";
53
53
  import { isExtensibleEnum } from "./type-expressions/get-enum-expression.js";
54
- import { isDiscriminatedUnion } from "./serialization/serializeUtils.js";
54
+ import {
55
+ getAllDiscriminatedValues,
56
+ isDiscriminatedUnion
57
+ } from "./serialization/serializeUtils.js";
55
58
  import { reportDiagnostic } from "../lib.js";
56
59
  import { getNamespaceFullName, NoTarget } from "@typespec/compiler";
57
60
  import {
@@ -66,6 +69,7 @@ import { resolveReference } from "../framework/reference.js";
66
69
  import { MultipartHelpers } from "./static-helpers-metadata.js";
67
70
  import { getAllAncestors } from "./helpers/operationHelpers.js";
68
71
  import { getAllProperties } from "./helpers/operationHelpers.js";
72
+ import { getDirectSubtypes } from "./helpers/typeHelpers.js";
69
73
 
70
74
  type InterfaceStructure = OptionalKind<InterfaceDeclarationStructure> & {
71
75
  extends?: string[];
@@ -458,6 +462,9 @@ function emitEnumMember(
458
462
 
459
463
  if (member.doc) {
460
464
  memberStructure.docs = [member.doc];
465
+ } else {
466
+ // Provide default documentation using the enum value when no explicit doc exists
467
+ memberStructure.docs = [String(member.value)];
461
468
  }
462
469
 
463
470
  return memberStructure;
@@ -474,7 +481,7 @@ function buildModelInterface(
474
481
  properties: type.properties
475
482
  .filter((p) => !isMetadata(context.program, p.__raw!))
476
483
  .map((p) => {
477
- return buildModelProperty(context, p);
484
+ return buildModelProperty(context, p, type);
478
485
  })
479
486
  } as InterfaceStructure;
480
487
 
@@ -621,17 +628,16 @@ export function normalizeModelName(
621
628
  }
622
629
 
623
630
  function buildModelPolymorphicType(context: SdkContext, type: SdkModelType) {
624
- if (!type.discriminatedSubtypes) {
631
+ // Only include direct subtypes in this union
632
+ const directSubtypes = getDirectSubtypes(type);
633
+ if (directSubtypes.length === 0) {
625
634
  return undefined;
626
635
  }
627
-
628
- const discriminatedSubtypes = Object.values(type.discriminatedSubtypes);
629
-
630
636
  const typeDeclaration: TypeAliasDeclarationStructure = {
631
637
  kind: StructureKind.TypeAlias,
632
638
  name: `${normalizeName(type.name, NameType.Interface)}Union`,
633
639
  isExported: true,
634
- type: discriminatedSubtypes
640
+ type: directSubtypes
635
641
  .filter((p) => {
636
642
  return (
637
643
  p.usage !== undefined &&
@@ -652,7 +658,8 @@ function buildModelPolymorphicType(context: SdkContext, type: SdkModelType) {
652
658
 
653
659
  function buildModelProperty(
654
660
  context: SdkContext,
655
- property: SdkModelPropertyType
661
+ property: SdkModelPropertyType,
662
+ model: SdkModelType
656
663
  ): PropertySignatureStructure {
657
664
  const normalizedPropName = normalizeModelPropertyName(context, property);
658
665
  if (
@@ -670,8 +677,18 @@ function buildModelProperty(
670
677
  }
671
678
 
672
679
  let typeExpression: string;
680
+ const allDiscriminatorValues = getAllDiscriminatedValues(model, property);
681
+
682
+ // We need refine the discriminator property if
683
+ // 1. it is discriminated union
684
+ // 2. it has other discriminator values except itself
685
+ if (isDiscriminatedUnion(model) && allDiscriminatorValues.length > 1) {
686
+ typeExpression = allDiscriminatorValues
687
+ .map((value) => `"${value}"`)
688
+ .join(" | ");
689
+ }
673
690
  // eslint-disable-next-line
674
- if (property.kind === "property" && property.isMultipartFileInput) {
691
+ else if (property.kind === "property" && property.isMultipartFileInput) {
675
692
  // eslint-disable-next-line
676
693
  const multipartOptions = property.multipartOptions;
677
694
  typeExpression = "{";
@@ -1051,15 +1051,21 @@ function getQueryParameters(
1051
1051
 
1052
1052
  for (const param of operationParameters) {
1053
1053
  if (param.kind === "query") {
1054
- parametersImplementation[param.kind].push({
1055
- paramMap: getParameterMap(dpgContext, {
1056
- ...param,
1057
- // TODO: remember to remove this hack once compiler gives us a name
1058
- // https://github.com/microsoft/typespec/issues/6743
1059
- serializedName: getUriTemplateQueryParamName(param.serializedName)
1060
- }),
1061
- param
1062
- });
1054
+ // Check if this parameter still exists in the corresponding method params (after override)
1055
+ if (
1056
+ param.correspondingMethodParams &&
1057
+ param.correspondingMethodParams.length > 0
1058
+ ) {
1059
+ parametersImplementation[param.kind].push({
1060
+ paramMap: getParameterMap(dpgContext, {
1061
+ ...param,
1062
+ // TODO: remember to remove this hack once compiler gives us a name
1063
+ // https://github.com/microsoft/typespec/issues/6743
1064
+ serializedName: getUriTemplateQueryParamName(param.serializedName)
1065
+ }),
1066
+ param
1067
+ });
1068
+ }
1063
1069
  }
1064
1070
  }
1065
1071
 
@@ -4,9 +4,20 @@ import {
4
4
  SdkCredentialParameter,
5
5
  SdkEndpointParameter,
6
6
  SdkMethodParameter,
7
+ SdkModelType,
7
8
  SdkType
8
9
  } from "@azure-tools/typespec-client-generator-core";
9
10
 
11
+ export function getDirectSubtypes(type: SdkModelType) {
12
+ if (!type.discriminatedSubtypes) {
13
+ return [];
14
+ }
15
+ // Filter out subtypes that extend from other discriminated subtypes (hierarchical inheritance)
16
+ return Object.values(type.discriminatedSubtypes).filter(
17
+ (subtype) => subtype.baseModel === type
18
+ );
19
+ }
20
+
10
21
  export function getAdditionalPropertiesType(
11
22
  type: SdkType | undefined
12
23
  ): SdkType | undefined {
@@ -20,6 +20,7 @@ import {
20
20
  import { NameType, normalizeName } from "@azure-tools/rlc-common";
21
21
  import { isAzureCoreErrorType } from "../../utils/modelUtils.js";
22
22
  import {
23
+ getAllDiscriminatedValues,
23
24
  isDiscriminatedUnion,
24
25
  isSupportedSerializeType,
25
26
  ModelSerializeOptions
@@ -27,7 +28,10 @@ import {
27
28
  import { SerializationHelpers } from "../static-helpers-metadata.js";
28
29
  import { refkey } from "../../framework/refkey.js";
29
30
  import { resolveReference } from "../../framework/reference.js";
30
- import { getAdditionalPropertiesType } from "../helpers/typeHelpers.js";
31
+ import {
32
+ getAdditionalPropertiesType,
33
+ getDirectSubtypes
34
+ } from "../helpers/typeHelpers.js";
31
35
 
32
36
  export function buildModelDeserializer(
33
37
  context: SdkContext,
@@ -208,8 +212,8 @@ function buildDiscriminatedUnionDeserializer(
208
212
  NameType.Operation,
209
213
  true
210
214
  )}Deserializer`;
211
- for (const key in type.discriminatedSubtypes) {
212
- const subType = type.discriminatedSubtypes[key]!;
215
+ const directSubtypes = getDirectSubtypes(type);
216
+ for (const subType of directSubtypes) {
213
217
  if (
214
218
  !subType.usage ||
215
219
  (subType.usage !== undefined &&
@@ -217,7 +221,11 @@ function buildDiscriminatedUnionDeserializer(
217
221
  ) {
218
222
  continue;
219
223
  }
220
- const discriminatedValue = subType.discriminatorValue!;
224
+ // get all discriminated values that is linked by this discriminator property
225
+ const discriminatedValues = getAllDiscriminatedValues(
226
+ subType,
227
+ type.discriminatorProperty
228
+ );
221
229
  const union = subType.discriminatedSubtypes ? "Union" : "";
222
230
  const subTypeName = `${normalizeName(subType.name, NameType.Interface, true)}${union}`;
223
231
  const subtypeDeserializerName = normalizeName(
@@ -226,8 +234,9 @@ function buildDiscriminatedUnionDeserializer(
226
234
  true
227
235
  );
228
236
 
237
+ const caseLabels = discriminatedValues.map((value) => `case "${value}":`);
229
238
  cases.push(`
230
- case "${discriminatedValue}":
239
+ ${caseLabels.join("\n")}
231
240
  return ${subtypeDeserializerName}(item as ${subTypeName});
232
241
  `);
233
242
  }
@@ -22,6 +22,7 @@ import {
22
22
  import { NameType, normalizeName } from "@azure-tools/rlc-common";
23
23
  import { isAzureCoreErrorType } from "../../utils/modelUtils.js";
24
24
  import {
25
+ getAllDiscriminatedValues,
25
26
  isDiscriminatedUnion,
26
27
  isSupportedSerializeType,
27
28
  ModelSerializeOptions
@@ -33,7 +34,10 @@ import {
33
34
  import { resolveReference } from "../../framework/reference.js";
34
35
  import { isOrExtendsHttpFile } from "@typespec/http";
35
36
  import { refkey } from "../../framework/refkey.js";
36
- import { getAdditionalPropertiesType } from "../helpers/typeHelpers.js";
37
+ import {
38
+ getAdditionalPropertiesType,
39
+ getDirectSubtypes
40
+ } from "../helpers/typeHelpers.js";
37
41
 
38
42
  export function buildModelSerializer(
39
43
  context: SdkContext,
@@ -215,8 +219,8 @@ function buildDiscriminatedUnionSerializer(
215
219
  NameType.Operation,
216
220
  true
217
221
  )}Serializer`;
218
- for (const key in type.discriminatedSubtypes) {
219
- const subType = type.discriminatedSubtypes[key]!;
222
+ const directSubtypes = getDirectSubtypes(type);
223
+ for (const subType of directSubtypes) {
220
224
  if (
221
225
  !subType.usage ||
222
226
  (subType.usage !== undefined &&
@@ -224,7 +228,11 @@ function buildDiscriminatedUnionSerializer(
224
228
  ) {
225
229
  continue;
226
230
  }
227
- const discriminatedValue = subType.discriminatorValue!;
231
+ // get all discriminated values that is linked by this discriminator property
232
+ const discriminatedValues = getAllDiscriminatedValues(
233
+ subType,
234
+ type.discriminatorProperty
235
+ );
228
236
  const union = subType.discriminatedSubtypes ? "Union" : "";
229
237
  const subTypeName = `${normalizeName(subType.name, NameType.Interface, true)}${union}`;
230
238
  const subtypeSerializerName = normalizeName(
@@ -233,8 +241,9 @@ function buildDiscriminatedUnionSerializer(
233
241
  true
234
242
  );
235
243
 
244
+ const caseLabels = discriminatedValues.map((value) => `case "${value}":`);
236
245
  cases.push(`
237
- case "${discriminatedValue}":
246
+ ${caseLabels.join("\n")}
238
247
  return ${subtypeSerializerName}(item as ${subTypeName});
239
248
  `);
240
249
  }
@@ -1,8 +1,48 @@
1
1
  import { getAllAncestors } from "../helpers/operationHelpers.js";
2
2
  import {
3
+ SdkModelPropertyType,
3
4
  SdkModelType,
4
5
  SdkType
5
6
  } from "@azure-tools/typespec-client-generator-core";
7
+ import { getDirectSubtypes } from "../helpers/typeHelpers.js";
8
+
9
+ /**
10
+ * Get all discriminated values for a given model type and given discriminator property.
11
+ * @param type The model type to get discriminated values from.
12
+ * @param discriminatorProperty The discriminator property to use for filtering.
13
+ * @returns An array of all discriminated values.
14
+ */
15
+ export function getAllDiscriminatedValues(
16
+ type: SdkModelType,
17
+ discriminatorProperty?: SdkModelPropertyType
18
+ ) {
19
+ if (!type.discriminatorValue) {
20
+ return [];
21
+ }
22
+ const values: string[] = [];
23
+ const children = [type];
24
+ while (children.length > 0) {
25
+ const model = children.shift()!;
26
+ // skip if no discriminator value
27
+ if (!model.discriminatorValue) {
28
+ continue;
29
+ }
30
+ // Check if this model is a subtype of the given discriminator property
31
+ if (
32
+ !!discriminatorProperty &&
33
+ model.baseModel?.discriminatorProperty?.name ===
34
+ discriminatorProperty?.name
35
+ ) {
36
+ values.push(model.discriminatorValue);
37
+ if (model.discriminatorProperty?.name === discriminatorProperty.name) {
38
+ // Traverse subtypes also if they have the same discriminator property
39
+ children.push(...getDirectSubtypes(model));
40
+ }
41
+ }
42
+ }
43
+
44
+ return values;
45
+ }
6
46
 
7
47
  export function isSupportedSerializeType(type: SdkType): boolean {
8
48
  return (
@@ -0,0 +1,77 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ import { SdkContext } from "./interfaces.js";
5
+ import { transformModularEmitterOptions } from "../modular/buildModularOptions.js";
6
+ import { getMethodHierarchiesMap } from "./operationUtil.js";
7
+ import { NameType, normalizeName } from "@azure-tools/rlc-common";
8
+
9
+ export function generateCrossLanguageDefinitionFile(dpgContext: SdkContext): {
10
+ CrossLanguagePackageId: string;
11
+ CrossLanguageDefinitionId: Record<string, string>;
12
+ } {
13
+ const modularSourcesRoot =
14
+ dpgContext.generationPathDetail?.modularSourcesDir ?? "src";
15
+ const emitterOptions = transformModularEmitterOptions(
16
+ dpgContext,
17
+ modularSourcesRoot,
18
+ {
19
+ casing: "camel"
20
+ }
21
+ );
22
+ const packageName =
23
+ emitterOptions.options?.packageDetails?.name ?? "package-name";
24
+ const CrossLanguageDefinitionId: Record<string, string> = {};
25
+
26
+ for (const model of dpgContext.sdkPackage.models) {
27
+ CrossLanguageDefinitionId[`${packageName}!${model.name}:interface`] =
28
+ model.crossLanguageDefinitionId;
29
+ }
30
+ for (const enm of dpgContext.sdkPackage.enums) {
31
+ CrossLanguageDefinitionId[`${packageName}!Known${enm.name}:enum`] =
32
+ enm.crossLanguageDefinitionId;
33
+ }
34
+ for (const union of dpgContext.sdkPackage.unions) {
35
+ CrossLanguageDefinitionId[`${packageName}!${union.name}:type`] =
36
+ union.crossLanguageDefinitionId;
37
+ }
38
+
39
+ for (const subClient of dpgContext.sdkPackage.clients) {
40
+ const clientName =
41
+ emitterOptions.options?.typespecTitleMap?.[subClient.name] ??
42
+ subClient.name;
43
+ const methodMap = getMethodHierarchiesMap(dpgContext, subClient);
44
+ for (const [prefixKey, operations] of methodMap) {
45
+ const prefixes = prefixKey.split("/");
46
+ if (prefixKey === "") {
47
+ for (const operation of operations) {
48
+ const { name } = operation;
49
+ const operationName = `${packageName}!${clientName}#${name}:member(1)`;
50
+ CrossLanguageDefinitionId[operationName] =
51
+ operation.crossLanguageDefinitionId;
52
+ }
53
+ } else {
54
+ // e,g., @azure/ai-client!ConnectionsOperations#getConnectionWithSecrets:member": "Azure.AI.Projects.Connections.getConnectionWithSecrets"
55
+ const rawGroupName = normalizeName(
56
+ prefixes[0] ?? "",
57
+ NameType.Interface
58
+ );
59
+ const propertyType = `${normalizeName(
60
+ rawGroupName,
61
+ NameType.OperationGroup
62
+ )}Operations`;
63
+ for (const operation of operations) {
64
+ const { name } = operation;
65
+ const operationName = `${packageName}!${propertyType}#${name}:member`;
66
+ CrossLanguageDefinitionId[operationName] =
67
+ operation.crossLanguageDefinitionId;
68
+ }
69
+ }
70
+ }
71
+ }
72
+
73
+ return {
74
+ CrossLanguagePackageId: dpgContext.sdkPackage.crossLanguagePackageId,
75
+ CrossLanguageDefinitionId
76
+ };
77
+ }