@azure-tools/typespec-ts 0.28.0 → 0.29.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 (94) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/src/index.d.ts +2 -0
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/index.js +24 -18
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/lib.d.ts +14 -4
  7. package/dist/src/lib.d.ts.map +1 -1
  8. package/dist/src/lib.js +9 -2
  9. package/dist/src/lib.js.map +1 -1
  10. package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
  11. package/dist/src/modular/buildClassicalClient.js +2 -0
  12. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  13. package/dist/src/modular/buildClassicalOperationGroups.d.ts.map +1 -1
  14. package/dist/src/modular/buildClassicalOperationGroups.js +3 -0
  15. package/dist/src/modular/buildClassicalOperationGroups.js.map +1 -1
  16. package/dist/src/modular/buildCodeModel.d.ts.map +1 -1
  17. package/dist/src/modular/buildCodeModel.js +80 -83
  18. package/dist/src/modular/buildCodeModel.js.map +1 -1
  19. package/dist/src/modular/buildLroFiles.d.ts +24 -0
  20. package/dist/src/modular/buildLroFiles.d.ts.map +1 -0
  21. package/dist/src/modular/buildLroFiles.js +399 -0
  22. package/dist/src/modular/buildLroFiles.js.map +1 -0
  23. package/dist/src/modular/buildOperations.d.ts +6 -0
  24. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  25. package/dist/src/modular/buildOperations.js +64 -5
  26. package/dist/src/modular/buildOperations.js.map +1 -1
  27. package/dist/src/modular/buildPagingFiles.js +3 -3
  28. package/dist/src/modular/buildPagingFiles.js.map +1 -1
  29. package/dist/src/modular/buildProjectFiles.d.ts +0 -3
  30. package/dist/src/modular/buildProjectFiles.d.ts.map +1 -1
  31. package/dist/src/modular/buildProjectFiles.js +0 -399
  32. package/dist/src/modular/buildProjectFiles.js.map +1 -1
  33. package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
  34. package/dist/src/modular/buildRootIndex.js +20 -0
  35. package/dist/src/modular/buildRootIndex.js.map +1 -1
  36. package/dist/src/modular/buildSubpathIndex.js +4 -3
  37. package/dist/src/modular/buildSubpathIndex.js.map +1 -1
  38. package/dist/src/modular/emitModels.d.ts +2 -0
  39. package/dist/src/modular/emitModels.d.ts.map +1 -1
  40. package/dist/src/modular/emitModels.js +73 -11
  41. package/dist/src/modular/emitModels.js.map +1 -1
  42. package/dist/src/modular/helpers/operationHelpers.d.ts +5 -5
  43. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  44. package/dist/src/modular/helpers/operationHelpers.js +171 -55
  45. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  46. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  47. package/dist/src/modular/helpers/typeHelpers.js +6 -1
  48. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  49. package/dist/src/modular/interfaces.d.ts +5 -0
  50. package/dist/src/modular/interfaces.d.ts.map +1 -1
  51. package/dist/src/modular/modularCodeModel.d.ts +9 -1
  52. package/dist/src/modular/modularCodeModel.d.ts.map +1 -1
  53. package/dist/src/transform/transformHelperFunctionDetails.js +1 -1
  54. package/dist/src/transform/transformParameters.js +2 -2
  55. package/dist/src/transform/transformParameters.js.map +1 -1
  56. package/dist/src/transform/transformPaths.js +1 -1
  57. package/dist/src/transform/transformPaths.js.map +1 -1
  58. package/dist/src/transform/transformResponses.js +2 -2
  59. package/dist/src/transform/transformResponses.js.map +1 -1
  60. package/dist/src/transform/transformSchemas.d.ts.map +1 -1
  61. package/dist/src/transform/transformSchemas.js +23 -31
  62. package/dist/src/transform/transformSchemas.js.map +1 -1
  63. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  64. package/dist/src/transform/transfromRLCOptions.js +8 -1
  65. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  66. package/dist/src/utils/modelUtils.d.ts +12 -2
  67. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  68. package/dist/src/utils/modelUtils.js +88 -49
  69. package/dist/src/utils/modelUtils.js.map +1 -1
  70. package/dist/tsconfig.tsbuildinfo +1 -1
  71. package/package.json +19 -18
  72. package/src/index.ts +36 -22
  73. package/src/lib.ts +10 -2
  74. package/src/modular/buildClassicalClient.ts +2 -0
  75. package/src/modular/buildClassicalOperationGroups.ts +4 -0
  76. package/src/modular/buildCodeModel.ts +100 -155
  77. package/src/modular/buildLroFiles.ts +433 -0
  78. package/src/modular/buildOperations.ts +91 -10
  79. package/src/modular/buildPagingFiles.ts +4 -4
  80. package/src/modular/buildProjectFiles.ts +0 -471
  81. package/src/modular/buildRootIndex.ts +49 -0
  82. package/src/modular/buildSubpathIndex.ts +4 -4
  83. package/src/modular/emitModels.ts +102 -15
  84. package/src/modular/helpers/operationHelpers.ts +207 -72
  85. package/src/modular/helpers/typeHelpers.ts +6 -2
  86. package/src/modular/interfaces.ts +6 -0
  87. package/src/modular/modularCodeModel.ts +10 -1
  88. package/src/transform/transformHelperFunctionDetails.ts +1 -1
  89. package/src/transform/transformParameters.ts +2 -2
  90. package/src/transform/transformPaths.ts +1 -1
  91. package/src/transform/transformResponses.ts +2 -2
  92. package/src/transform/transformSchemas.ts +22 -33
  93. package/src/transform/transfromRLCOptions.ts +10 -1
  94. package/src/utils/modelUtils.ts +107 -46
@@ -15,7 +15,7 @@ import {
15
15
  getLroLogicalResponseName,
16
16
  Imports
17
17
  } from "@azure-tools/rlc-common";
18
- import { getDoc, ignoreDiagnostics } from "@typespec/compiler";
18
+ import { getDoc, ignoreDiagnostics, isVoidType } from "@typespec/compiler";
19
19
  import {
20
20
  getHttpOperation,
21
21
  HttpOperation,
@@ -174,7 +174,7 @@ function transformBody(
174
174
  let fromCore = false;
175
175
  for (const data of response.responses) {
176
176
  const body = data?.body;
177
- if (!body) {
177
+ if (!body || isVoidType(body.type)) {
178
178
  continue;
179
179
  }
180
180
  const hasBinaryContent = body.contentTypes.some((contentType) =>
@@ -27,9 +27,9 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
27
27
  SchemaContext[]
28
28
  >();
29
29
  const schemaMap: Map<any, any> = new Map<any, any>();
30
+ const usageMap = new Map<Type, SchemaContext[]>();
30
31
  const requestBodySet = new Set<Type>();
31
32
  const contentTypeMap = new Map<Type, KnownMediaType[]>();
32
- const modelKey = Symbol("typescript-models-" + client.name);
33
33
  const clientOperations = listOperationsInOperationGroup(dpgContext, client);
34
34
  for (const clientOp of clientOperations) {
35
35
  const route = ignoreDiagnostics(getHttpOperation(program, clientOp));
@@ -77,7 +77,7 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
77
77
  getGeneratedModels(bodyModel, SchemaContext.Input);
78
78
  }
79
79
  for (const resp of route.responses) {
80
- if (isAzureCoreErrorType(resp.type)) {
80
+ if (isAzureCoreErrorType(dpgContext.program, resp.type)) {
81
81
  continue;
82
82
  }
83
83
  for (const resps of resp.responses) {
@@ -87,12 +87,11 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
87
87
  getGeneratedModels(value, SchemaContext.Output);
88
88
  }
89
89
  }
90
-
91
- const respModel = resps.body;
90
+ const respModel = resps?.body?.type;
92
91
  if (!respModel) {
93
92
  continue;
94
93
  }
95
- getGeneratedModels(respModel.type, SchemaContext.Output);
94
+ getGeneratedModels(respModel, SchemaContext.Output);
96
95
  }
97
96
  }
98
97
  }
@@ -112,7 +111,7 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
112
111
  }
113
112
  }
114
113
  transformHostParameters();
115
- program.stateMap(modelKey).forEach((context, tspModel) => {
114
+ usageMap.forEach((context, tspModel) => {
116
115
  const model = getSchemaForType(dpgContext, tspModel, {
117
116
  usage: context,
118
117
  isRequestBody: requestBodySet.has(tspModel),
@@ -127,22 +126,19 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
127
126
  }
128
127
  const pureModel = JSON.stringify(trimUsage(model));
129
128
  schemaMap.set(pureModel, model);
130
- let usage = schemas.get(pureModel) ?? [];
131
- if (!usage?.includes(context)) {
132
- usage = usage.concat(context as SchemaContext[]);
133
- }
134
- schemas.set(pureModel, usage);
129
+ const usageSet = new Set((schemas.get(pureModel) ?? []).concat(context));
130
+ schemas.set(pureModel, Array.from(usageSet));
135
131
  });
136
132
 
137
133
  function setModelMap(type: Type, schemaContext: SchemaContext) {
138
- if (program.stateMap(modelKey).get(type)) {
139
- const context = program.stateMap(modelKey).get(type);
134
+ if (usageMap.get(type)) {
135
+ const context = usageMap.get(type);
140
136
  if (context && context.indexOf(schemaContext) === -1) {
141
137
  context.push(schemaContext);
142
- program.stateMap(modelKey).set(type, context);
138
+ usageMap.set(type, context);
143
139
  }
144
140
  } else {
145
- program.stateMap(modelKey).set(type, [schemaContext]);
141
+ usageMap.set(type, [schemaContext]);
146
142
  }
147
143
  }
148
144
  function getGeneratedModels(model: Type, context: SchemaContext) {
@@ -151,21 +147,18 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
151
147
  const indexer = (model as Model).indexer;
152
148
  if (
153
149
  indexer?.value &&
154
- (!program.stateMap(modelKey).get(indexer?.value) ||
155
- !program
156
- .stateMap(modelKey)
157
- .get(indexer?.value)
158
- ?.includes(context))
150
+ (!usageMap.get(indexer?.value) ||
151
+ !usageMap.get(indexer?.value)?.includes(context))
159
152
  ) {
160
153
  getGeneratedModels(indexer.value, context);
161
154
  }
162
155
  for (const prop of model.properties) {
163
156
  const [, propType] = prop;
164
- if (program.stateMap(modelKey).get(propType.type)?.includes(context)) {
157
+ if (usageMap.get(propType.type)?.includes(context)) {
165
158
  continue;
166
159
  }
167
160
  if (propType.type.kind === "Model") {
168
- if (isAzureCoreErrorType(propType.type)) {
161
+ if (isAzureCoreErrorType(dpgContext.program, propType.type)) {
169
162
  continue;
170
163
  }
171
164
  getGeneratedModels(propType.type, context);
@@ -176,11 +169,8 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
176
169
  (variant.type.kind === "Model" ||
177
170
  variant.type.kind === "Union" ||
178
171
  variant.type.kind === "Enum") &&
179
- (!program.stateMap(modelKey).get(variant.type) ||
180
- !program
181
- .stateMap(modelKey)
182
- .get(variant.type)
183
- ?.includes(context))
172
+ (!usageMap.get(variant.type) ||
173
+ !usageMap.get(variant.type)?.includes(context))
184
174
  ) {
185
175
  getGeneratedModels(variant.type, context);
186
176
  }
@@ -197,8 +187,8 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
197
187
  if (
198
188
  baseModel &&
199
189
  baseModel.kind === "Model" &&
200
- (!program.stateMap(modelKey).get(baseModel) ||
201
- !program.stateMap(modelKey).get(baseModel)?.includes(context))
190
+ (!usageMap.get(baseModel) ||
191
+ !usageMap.get(baseModel)?.includes(context))
202
192
  ) {
203
193
  getGeneratedModels(baseModel, context);
204
194
  }
@@ -210,8 +200,7 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
210
200
  for (const child of derivedModels) {
211
201
  if (
212
202
  child.kind === "Model" &&
213
- (!program.stateMap(modelKey).get(child) ||
214
- !program.stateMap(modelKey).get(child)?.includes(context))
203
+ (!usageMap.get(child) || !usageMap.get(child)?.includes(context))
215
204
  ) {
216
205
  getGeneratedModels(child, context);
217
206
  }
@@ -221,8 +210,8 @@ export function transformSchemas(client: SdkClient, dpgContext: SdkContext) {
221
210
  for (const variant of variants) {
222
211
  if (
223
212
  (variant.type.kind === "Model" || variant.type.kind === "Union") &&
224
- (!program.stateMap(modelKey).get(variant.type) ||
225
- !program.stateMap(modelKey).get(variant.type)?.includes(context))
213
+ (!usageMap.get(variant.type) ||
214
+ !usageMap.get(variant.type)?.includes(context))
226
215
  ) {
227
216
  getGeneratedModels(variant.type, context);
228
217
  }
@@ -85,7 +85,8 @@ function extractRLCOptions(
85
85
  sourceFrom: "TypeSpec",
86
86
  enableOperationGroup,
87
87
  enableModelNamespace,
88
- hierarchyClient
88
+ hierarchyClient,
89
+ azureArm: dpgContext.arm
89
90
  };
90
91
  }
91
92
 
@@ -129,6 +130,14 @@ function processAuth(program: Program) {
129
130
  target: NoTarget
130
131
  });
131
132
  }
133
+ // ignore the user_impersonation scope
134
+ if (
135
+ flow.scopes.length === 1 &&
136
+ flow.scopes[0] &&
137
+ flow.scopes[0].value.toLowerCase() === "user_impersonation"
138
+ ) {
139
+ return securityInfo;
140
+ }
132
141
  securityInfo.credentialScopes.push(
133
142
  ...flow.scopes.map((item) => {
134
143
  return item.value;
@@ -231,7 +231,10 @@ export function getSchemaForType(
231
231
  }
232
232
  reportDiagnostic(program, {
233
233
  code: "invalid-schema",
234
- format: { type: type.kind },
234
+ format: {
235
+ type: type.kind,
236
+ property: options?.relevantProperty?.name ?? ""
237
+ },
235
238
  target: type
236
239
  });
237
240
  return undefined;
@@ -242,18 +245,13 @@ export function getEffectiveModelFromType(program: Program, type: Type): Type {
242
245
  * set of properties when non-schema properties are excluded.
243
246
  */
244
247
  if (type.kind === "Model" && type.name === "") {
245
- const effective = getEffectiveModelType(program, type, isSchemaProperty);
248
+ const effective = getEffectiveModelType(program, type, (property) =>
249
+ isSchemaProperty(program, property)
250
+ );
246
251
  if (effective.name) {
247
252
  return effective;
248
253
  }
249
254
  }
250
- function isSchemaProperty(property: ModelProperty) {
251
- const headerInfo = getHeaderFieldName(program, property);
252
- const queryInfo = getQueryParamName(program, property);
253
- const pathInfo = getPathParamName(program, property);
254
- const statusCodeInfo = isStatusCode(program, property);
255
- return !(headerInfo || queryInfo || pathInfo || statusCodeInfo);
256
- }
257
255
  return type;
258
256
  }
259
257
  export function includeDerivedModel(
@@ -554,19 +552,6 @@ function validateDiscriminator(
554
552
  }
555
553
  return retVals.every((v) => v);
556
554
  }
557
- /**
558
- * A "schema property" here is a property that is emitted to OpenAPI schema.
559
- *
560
- * Headers, parameters, status codes are not schema properties even they are
561
- * represented as properties in typespec.
562
- */
563
- function isSchemaProperty(program: Program, property: ModelProperty) {
564
- const headerInfo = getHeaderFieldName(program, property);
565
- const queryInfo = getQueryParamName(program, property);
566
- const pathInfo = getPathParamName(program, property);
567
- const statusCodeinfo = isStatusCode(program, property);
568
- return !(headerInfo || queryInfo || pathInfo || statusCodeinfo);
569
- }
570
555
 
571
556
  function getSchemaForModel(
572
557
  dpgContext: SdkContext,
@@ -617,7 +602,7 @@ function getSchemaForModel(
617
602
 
618
603
  const isMultipartBody = isMediaTypeMultipartFormData(contentTypes ?? []);
619
604
 
620
- const isCoreModel = isAzureCoreErrorType(model);
605
+ const isCoreModel = isAzureCoreErrorType(program, model);
621
606
  const modelSchema: ObjectSchema = {
622
607
  name: isCoreModel
623
608
  ? name
@@ -819,20 +804,24 @@ function getSchemaForModel(
819
804
  }
820
805
 
821
806
  if (model.baseModel) {
822
- modelSchema.parents = {
823
- all: [
824
- getSchemaForType(dpgContext, model.baseModel, {
825
- usage,
826
- needRef: true
827
- })
828
- ],
829
- immediate: [
830
- getSchemaForType(dpgContext, model.baseModel, {
831
- usage,
832
- needRef: true
833
- })
834
- ]
835
- };
807
+ if (modelSchema.parents === undefined) {
808
+ modelSchema.parents = {
809
+ all: [],
810
+ immediate: []
811
+ };
812
+ }
813
+ modelSchema.parents.all?.push(
814
+ getSchemaForType(dpgContext, model.baseModel, {
815
+ usage,
816
+ needRef: true
817
+ })
818
+ );
819
+ modelSchema.parents.immediate?.push(
820
+ getSchemaForType(dpgContext, model.baseModel, {
821
+ usage,
822
+ needRef: true
823
+ })
824
+ );
836
825
  }
837
826
  return modelSchema;
838
827
  }
@@ -1337,11 +1326,7 @@ export function getSerializeTypeName(
1337
1326
  "Date | string",
1338
1327
  "string"
1339
1328
  );
1340
- const canSerialize = schema.enum
1341
- ? schema.enum.every((type) => {
1342
- return isSerializable(type) || type.type === "null";
1343
- })
1344
- : isSerializable(schema);
1329
+ const canSerialize = isSerializable(schema);
1345
1330
  if (canSerialize) {
1346
1331
  return schema.alias ? typeName : formattedName;
1347
1332
  }
@@ -1352,6 +1337,11 @@ export function getSerializeTypeName(
1352
1337
  });
1353
1338
  return "string";
1354
1339
  function isSerializable(type: any) {
1340
+ if (type.enum) {
1341
+ return type.enum.every((i: any) => {
1342
+ return isSerializable(i) || i.type === "null";
1343
+ });
1344
+ }
1355
1345
  return (
1356
1346
  ["string", "number", "boolean"].includes(type.type) || type.isConstant
1357
1347
  );
@@ -1582,16 +1572,40 @@ export function trimUsage(model: any) {
1582
1572
  return ordered;
1583
1573
  }
1584
1574
 
1585
- export function isAzureCoreErrorType(t?: Type): boolean {
1575
+ export function buildCoreTypeInfo(program: Program, t?: Type) {
1576
+ return isAzureCoreErrorType(program, t)
1577
+ ? "ErrorType"
1578
+ : isAzureCoreLroType(t)
1579
+ ? "LroType"
1580
+ : undefined;
1581
+ }
1582
+
1583
+ export function isAzureCoreErrorType(program: Program, t?: Type): boolean {
1584
+ if (!t || t.kind !== "Model") {
1585
+ return false;
1586
+ }
1587
+ const effective = getEffectiveSchemaType(program, t);
1586
1588
  if (
1587
- t?.kind !== "Model" ||
1588
- !["error", "errorresponse", "innererror"].includes(t.name.toLowerCase())
1589
+ !["error", "errorresponse", "innererror"].includes(
1590
+ effective.name.toLowerCase()
1591
+ )
1589
1592
  )
1590
1593
  return false;
1594
+ return isAzureCoreFoundationsNamespace(effective);
1595
+ }
1596
+
1597
+ // Check if the type in the Azure.Core.Foundations has an LRO type in core
1598
+ export function isAzureCoreLroType(t?: Type): boolean {
1599
+ if (t?.kind !== "Enum" || !["operationstate"].includes(t.name.toLowerCase()))
1600
+ return false;
1601
+ return isAzureCoreFoundationsNamespace(t);
1602
+ }
1603
+
1604
+ function isAzureCoreFoundationsNamespace(t?: Type): boolean {
1591
1605
  const namespaces = ".Azure.Core.Foundations".split(".");
1592
1606
  while (
1593
1607
  namespaces.length > 0 &&
1594
- (t?.kind === "Model" || t?.kind === "Namespace") &&
1608
+ (t?.kind === "Model" || t?.kind === "Enum" || t?.kind === "Namespace") &&
1595
1609
  t.namespace?.name === namespaces.pop()
1596
1610
  ) {
1597
1611
  t = t.namespace;
@@ -1699,3 +1713,50 @@ function getMultipartInlineSignature(
1699
1713
 
1700
1714
  return `FormData | Array<${types}>`;
1701
1715
  }
1716
+
1717
+ /**
1718
+ * A "schema property" here is a property that is emitted to OpenAPI schema.
1719
+ *
1720
+ * Headers, parameters, status codes are not schema properties even they are
1721
+ * represented as properties in typespec.
1722
+ */
1723
+ export function isSchemaProperty(
1724
+ program: Program,
1725
+ property: ModelProperty
1726
+ ): boolean {
1727
+ const headerInfo = getHeaderFieldName(program, property);
1728
+ const queryInfo = getQueryParamName(program, property);
1729
+ const pathInfo = getPathParamName(program, property);
1730
+ const statusCodeInfo = isStatusCode(program, property);
1731
+ return !(headerInfo || queryInfo || pathInfo || statusCodeInfo);
1732
+ }
1733
+
1734
+ export function getEffectiveSchemaType(
1735
+ program: Program,
1736
+ type: Model | Union
1737
+ ): Model {
1738
+ // If type is an anonymous model, tries to find a named model that has the same properties
1739
+ let effective: Model | undefined = undefined;
1740
+ if (type.kind === "Union") {
1741
+ const nonNullOptions = [...type.variants.values()]
1742
+ .map((x) => x.type)
1743
+ .filter((t) => !isNullType(t));
1744
+ if (
1745
+ nonNullOptions.length === 1 &&
1746
+ nonNullOptions[0]?.kind === "Model" &&
1747
+ nonNullOptions[0]?.name === ""
1748
+ ) {
1749
+ effective = getEffectiveModelType(program, nonNullOptions[0]);
1750
+ }
1751
+ return type as any;
1752
+ } else if (type.name === "") {
1753
+ effective = getEffectiveModelType(program, type, (property) =>
1754
+ isSchemaProperty(program, property)
1755
+ );
1756
+ }
1757
+
1758
+ if (effective?.name) {
1759
+ return effective;
1760
+ }
1761
+ return type as Model;
1762
+ }