@microsoft/m365-spec-parser 0.2.5 → 0.2.6-alpha.0b985f7da.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.
@@ -38,11 +38,8 @@ var ErrorType;
38
38
  ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
39
39
  ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
40
40
  ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
41
- ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
42
41
  ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
43
42
  ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
44
- ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
45
- ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
46
43
  ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
47
44
  ErrorType["NoParameter"] = "no-parameter";
48
45
  ErrorType["NoAPIInfo"] = "no-api-info";
@@ -62,6 +59,7 @@ var WarningType;
62
59
  WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
63
60
  WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
64
61
  WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
62
+ WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
65
63
  WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
66
64
  WarningType["Unknown"] = "unknown";
67
65
  })(WarningType || (WarningType = {}));
@@ -101,6 +99,7 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
101
99
  ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
102
100
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
103
101
  ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
102
+ ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
104
103
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
105
104
  ConstantString.FuncDescriptionTooLong = "The description of the function '%s' is too long. The current length is %s characters, while the maximum allowed length is %s characters.";
106
105
  ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
@@ -110,17 +109,12 @@ ConstantString.WrappedCardResponseLayout = "list";
110
109
  ConstantString.GetMethod = "get";
111
110
  ConstantString.PostMethod = "post";
112
111
  ConstantString.AdaptiveCardVersion = "1.5";
113
- ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
112
+ ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
114
113
  ConstantString.AdaptiveCardType = "AdaptiveCard";
115
114
  ConstantString.TextBlockType = "TextBlock";
116
115
  ConstantString.ImageType = "Image";
117
116
  ConstantString.ContainerType = "Container";
118
- ConstantString.RegistrationIdPostfix = {
119
- apiKey: "REGISTRATION_ID",
120
- oauth2: "CONFIGURATION_ID",
121
- http: "REGISTRATION_ID",
122
- openIdConnect: "REGISTRATION_ID",
123
- };
117
+ ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
124
118
  ConstantString.ResponseCodeFor20X = [
125
119
  "200",
126
120
  "201",
@@ -132,6 +126,7 @@ ConstantString.ResponseCodeFor20X = [
132
126
  "207",
133
127
  "208",
134
128
  "226",
129
+ "2XX",
135
130
  "default",
136
131
  ];
137
132
  ConstantString.AllOperationMethods = [
@@ -197,17 +192,6 @@ class SpecParserError extends Error {
197
192
 
198
193
  // Copyright (c) Microsoft Corporation.
199
194
  class Utils {
200
- static hasNestedObjectInSchema(schema) {
201
- if (this.isObjectSchema(schema)) {
202
- for (const property in schema.properties) {
203
- const nestedSchema = schema.properties[property];
204
- if (this.isObjectSchema(nestedSchema)) {
205
- return true;
206
- }
207
- }
208
- }
209
- return false;
210
- }
211
195
  static isObjectSchema(schema) {
212
196
  return schema.type === "object" || (!schema.type && !!schema.properties);
213
197
  }
@@ -220,11 +204,32 @@ class Utils {
220
204
  static isAPIKeyAuth(authScheme) {
221
205
  return authScheme.type === "apiKey";
222
206
  }
207
+ static isAPIKeyAuthButNotInCookie(authScheme) {
208
+ return authScheme.type === "apiKey" && authScheme.in !== "cookie";
209
+ }
223
210
  static isOAuthWithAuthCodeFlow(authScheme) {
224
211
  return !!(authScheme.type === "oauth2" &&
225
212
  authScheme.flows &&
226
213
  authScheme.flows.authorizationCode);
227
214
  }
215
+ static isNotSupportedAuth(authSchemeArray) {
216
+ if (authSchemeArray.length === 0) {
217
+ return false;
218
+ }
219
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
220
+ return true;
221
+ }
222
+ for (const auths of authSchemeArray) {
223
+ if (auths.length === 1) {
224
+ if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
225
+ Utils.isBearerTokenAuth(auths[0].authScheme) ||
226
+ Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
227
+ return false;
228
+ }
229
+ }
230
+ }
231
+ return true;
232
+ }
228
233
  static getAuthArray(securities, spec) {
229
234
  var _a;
230
235
  const result = [];
@@ -249,6 +254,20 @@ class Utils {
249
254
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
250
255
  return result;
251
256
  }
257
+ static getAuthMap(spec) {
258
+ const authMap = {};
259
+ for (const url in spec.paths) {
260
+ for (const method in spec.paths[url]) {
261
+ const operation = spec.paths[url][method];
262
+ const authArray = Utils.getAuthArray(operation.security, spec);
263
+ if (authArray && authArray.length > 0) {
264
+ const currentAuth = authArray[0][0];
265
+ authMap[operation.operationId] = currentAuth;
266
+ }
267
+ }
268
+ }
269
+ return authMap;
270
+ }
252
271
  static getAuthInfo(spec) {
253
272
  let authInfo = undefined;
254
273
  for (const url in spec.paths) {
@@ -277,27 +296,33 @@ class Utils {
277
296
  let multipleMediaType = false;
278
297
  for (const code of ConstantString.ResponseCodeFor20X) {
279
298
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
280
- if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
281
- for (const contentType of Object.keys(responseObject.content)) {
282
- // json media type can also be "application/json; charset=utf-8"
283
- if (contentType.indexOf("application/json") >= 0) {
284
- multipleMediaType = false;
285
- json = responseObject.content[contentType];
286
- if (Utils.containMultipleMediaTypes(responseObject)) {
287
- multipleMediaType = true;
288
- if (!allowMultipleMediaType) {
289
- json = {};
290
- }
291
- }
292
- else {
293
- return { json, multipleMediaType };
294
- }
295
- }
296
- }
299
+ if (!responseObject) {
300
+ continue;
301
+ }
302
+ multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
303
+ if (!allowMultipleMediaType && multipleMediaType) {
304
+ json = {};
305
+ continue;
306
+ }
307
+ const mediaObj = Utils.getJsonContentType(responseObject);
308
+ if (Object.keys(mediaObj).length > 0) {
309
+ json = mediaObj;
310
+ return { json, multipleMediaType };
297
311
  }
298
312
  }
299
313
  return { json, multipleMediaType };
300
314
  }
315
+ static getJsonContentType(responseObject) {
316
+ if (responseObject.content) {
317
+ for (const contentType of Object.keys(responseObject.content)) {
318
+ // json media type can also be "application/json; charset=utf-8"
319
+ if (contentType.indexOf("application/json") >= 0) {
320
+ return responseObject.content[contentType];
321
+ }
322
+ }
323
+ }
324
+ return {};
325
+ }
301
326
  static convertPathToCamelCase(path) {
302
327
  const pathSegments = path.split(/[./{]/);
303
328
  const camelCaseSegments = pathSegments.map((segment) => {
@@ -333,7 +358,7 @@ class Utils {
333
358
  }
334
359
  return newStr;
335
360
  }
336
- static checkServerUrl(servers) {
361
+ static checkServerUrl(servers, allowHttp = false) {
337
362
  const errors = [];
338
363
  let serverUrl;
339
364
  try {
@@ -356,8 +381,7 @@ class Utils {
356
381
  data: servers,
357
382
  });
358
383
  }
359
- else if (protocol !== "https:") {
360
- // Http server url is not supported
384
+ else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
361
385
  const protocolString = protocol.slice(0, -1);
362
386
  errors.push({
363
387
  type: ErrorType.UrlProtocolNotSupported,
@@ -373,10 +397,11 @@ class Utils {
373
397
  let hasTopLevelServers = false;
374
398
  let hasPathLevelServers = false;
375
399
  let hasOperationLevelServers = false;
400
+ const allowHttp = options.projectType === ProjectType.Copilot;
376
401
  if (spec.servers && spec.servers.length >= 1) {
377
402
  hasTopLevelServers = true;
378
403
  // for multiple server, we only use the first url
379
- const serverErrors = Utils.checkServerUrl(spec.servers);
404
+ const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
380
405
  errors.push(...serverErrors);
381
406
  }
382
407
  const paths = spec.paths;
@@ -384,7 +409,7 @@ class Utils {
384
409
  const methods = paths[path];
385
410
  if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
386
411
  hasPathLevelServers = true;
387
- const serverErrors = Utils.checkServerUrl(methods.servers);
412
+ const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
388
413
  errors.push(...serverErrors);
389
414
  }
390
415
  for (const method in methods) {
@@ -392,7 +417,7 @@ class Utils {
392
417
  if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
393
418
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
394
419
  hasOperationLevelServers = true;
395
- const serverErrors = Utils.checkServerUrl(operationObject.servers);
420
+ const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
396
421
  errors.push(...serverErrors);
397
422
  }
398
423
  }
@@ -681,22 +706,6 @@ class Validator {
681
706
  }
682
707
  return result;
683
708
  }
684
- validateResponse(method, path) {
685
- const result = { isValid: true, reason: [] };
686
- const operationObject = this.spec.paths[path][method];
687
- const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
688
- if (this.options.projectType === ProjectType.SME) {
689
- // only support response body only contains “application/json” content type
690
- if (multipleMediaType) {
691
- result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
692
- }
693
- else if (Object.keys(json).length === 0) {
694
- // response body should not be empty
695
- result.reason.push(ErrorType.ResponseJsonIsEmpty);
696
- }
697
- }
698
- return result;
699
- }
700
709
  validateServer(method, path) {
701
710
  const result = { isValid: true, reason: [] };
702
711
  const serverObj = Utils.getServerObject(this.spec, method, path);
@@ -705,8 +714,8 @@ class Validator {
705
714
  result.reason.push(ErrorType.NoServerInformation);
706
715
  }
707
716
  else {
708
- // server url should be absolute url with https protocol
709
- const serverValidateResult = Utils.checkServerUrl([serverObj]);
717
+ const allowHttp = this.projectType === ProjectType.Copilot;
718
+ const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
710
719
  result.reason.push(...serverValidateResult.map((item) => item.type));
711
720
  }
712
721
  return result;
@@ -729,6 +738,9 @@ class Validator {
729
738
  reason: [ErrorType.MultipleAuthNotSupported],
730
739
  };
731
740
  }
741
+ if (this.projectType === ProjectType.Copilot) {
742
+ return { isValid: true, reason: [] };
743
+ }
732
744
  for (const auths of authSchemeArray) {
733
745
  if (auths.length === 1) {
734
746
  if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
@@ -741,114 +753,6 @@ class Validator {
741
753
  }
742
754
  return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
743
755
  }
744
- checkPostBodySchema(schema, isRequired = false) {
745
- var _a;
746
- const paramResult = {
747
- requiredNum: 0,
748
- optionalNum: 0,
749
- isValid: true,
750
- reason: [],
751
- };
752
- if (Object.keys(schema).length === 0) {
753
- return paramResult;
754
- }
755
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
756
- const isCopilot = this.projectType === ProjectType.Copilot;
757
- if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
758
- paramResult.isValid = false;
759
- paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
760
- return paramResult;
761
- }
762
- if (schema.type === "string" ||
763
- schema.type === "integer" ||
764
- schema.type === "boolean" ||
765
- schema.type === "number") {
766
- if (isRequiredWithoutDefault) {
767
- paramResult.requiredNum = paramResult.requiredNum + 1;
768
- }
769
- else {
770
- paramResult.optionalNum = paramResult.optionalNum + 1;
771
- }
772
- }
773
- else if (Utils.isObjectSchema(schema)) {
774
- const { properties } = schema;
775
- for (const property in properties) {
776
- let isRequired = false;
777
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
778
- isRequired = true;
779
- }
780
- const result = this.checkPostBodySchema(properties[property], isRequired);
781
- paramResult.requiredNum += result.requiredNum;
782
- paramResult.optionalNum += result.optionalNum;
783
- paramResult.isValid = paramResult.isValid && result.isValid;
784
- paramResult.reason.push(...result.reason);
785
- }
786
- }
787
- else {
788
- if (isRequiredWithoutDefault && !isCopilot) {
789
- paramResult.isValid = false;
790
- paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
791
- }
792
- }
793
- return paramResult;
794
- }
795
- checkParamSchema(paramObject) {
796
- const paramResult = {
797
- requiredNum: 0,
798
- optionalNum: 0,
799
- isValid: true,
800
- reason: [],
801
- };
802
- if (!paramObject) {
803
- return paramResult;
804
- }
805
- const isCopilot = this.projectType === ProjectType.Copilot;
806
- for (let i = 0; i < paramObject.length; i++) {
807
- const param = paramObject[i];
808
- const schema = param.schema;
809
- if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
810
- paramResult.isValid = false;
811
- paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
812
- continue;
813
- }
814
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
815
- if (isCopilot) {
816
- if (isRequiredWithoutDefault) {
817
- paramResult.requiredNum = paramResult.requiredNum + 1;
818
- }
819
- else {
820
- paramResult.optionalNum = paramResult.optionalNum + 1;
821
- }
822
- continue;
823
- }
824
- if (param.in === "header" || param.in === "cookie") {
825
- if (isRequiredWithoutDefault) {
826
- paramResult.isValid = false;
827
- paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
828
- }
829
- continue;
830
- }
831
- if (schema.type !== "boolean" &&
832
- schema.type !== "string" &&
833
- schema.type !== "number" &&
834
- schema.type !== "integer") {
835
- if (isRequiredWithoutDefault) {
836
- paramResult.isValid = false;
837
- paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
838
- }
839
- continue;
840
- }
841
- if (param.in === "query" || param.in === "path") {
842
- if (isRequiredWithoutDefault) {
843
- paramResult.requiredNum = paramResult.requiredNum + 1;
844
- }
845
- else {
846
- paramResult.optionalNum = paramResult.optionalNum + 1;
847
- }
848
- }
849
- }
850
- return paramResult;
851
- }
852
756
  }
853
757
 
854
758
  // Copyright (c) Microsoft Corporation.
@@ -858,7 +762,6 @@ class CopilotValidator extends Validator {
858
762
  this.projectType = ProjectType.Copilot;
859
763
  this.options = options;
860
764
  this.spec = spec;
861
- this.checkCircularReference();
862
765
  }
863
766
  validateSpec() {
864
767
  const result = { errors: [], warnings: [] };
@@ -884,10 +787,6 @@ class CopilotValidator extends Validator {
884
787
  if (!methodAndPathResult.isValid) {
885
788
  return methodAndPathResult;
886
789
  }
887
- const circularReferenceResult = this.validateCircularReference(method, path);
888
- if (!circularReferenceResult.isValid) {
889
- return circularReferenceResult;
890
- }
891
790
  const operationObject = this.spec.paths[path][method];
892
791
  // validate auth
893
792
  const authCheckResult = this.validateAuth(method, path);
@@ -899,24 +798,6 @@ class CopilotValidator extends Validator {
899
798
  // validate server
900
799
  const validateServerResult = this.validateServer(method, path);
901
800
  result.reason.push(...validateServerResult.reason);
902
- // validate response
903
- const validateResponseResult = this.validateResponse(method, path);
904
- result.reason.push(...validateResponseResult.reason);
905
- // validate requestBody
906
- const requestBody = operationObject.requestBody;
907
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
908
- if (requestJsonBody) {
909
- const requestBodySchema = requestJsonBody.schema;
910
- if (!Utils.isObjectSchema(requestBodySchema)) {
911
- result.reason.push(ErrorType.PostBodySchemaIsNotJson);
912
- }
913
- const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
914
- result.reason.push(...requestBodyParamResult.reason);
915
- }
916
- // validate parameters
917
- const paramObject = operationObject.parameters;
918
- const paramResult = this.checkParamSchema(paramObject);
919
- result.reason.push(...paramResult.reason);
920
801
  if (result.reason.length > 0) {
921
802
  result.isValid = false;
922
803
  }
@@ -1008,6 +889,108 @@ class SMEValidator extends Validator {
1008
889
  }
1009
890
  return result;
1010
891
  }
892
+ validateResponse(method, path) {
893
+ const result = { isValid: true, reason: [] };
894
+ const operationObject = this.spec.paths[path][method];
895
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
896
+ // only support response body only contains “application/json” content type
897
+ if (multipleMediaType) {
898
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
899
+ }
900
+ else if (Object.keys(json).length === 0) {
901
+ // response body should not be empty
902
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
903
+ }
904
+ return result;
905
+ }
906
+ checkPostBodySchema(schema, isRequired = false) {
907
+ var _a;
908
+ const paramResult = {
909
+ requiredNum: 0,
910
+ optionalNum: 0,
911
+ isValid: true,
912
+ reason: [],
913
+ };
914
+ if (Object.keys(schema).length === 0) {
915
+ return paramResult;
916
+ }
917
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
918
+ const isCopilot = this.projectType === ProjectType.Copilot;
919
+ if (schema.type === "string" ||
920
+ schema.type === "integer" ||
921
+ schema.type === "boolean" ||
922
+ schema.type === "number") {
923
+ if (isRequiredWithoutDefault) {
924
+ paramResult.requiredNum = paramResult.requiredNum + 1;
925
+ }
926
+ else {
927
+ paramResult.optionalNum = paramResult.optionalNum + 1;
928
+ }
929
+ }
930
+ else if (Utils.isObjectSchema(schema)) {
931
+ const { properties } = schema;
932
+ for (const property in properties) {
933
+ let isRequired = false;
934
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
935
+ isRequired = true;
936
+ }
937
+ const result = this.checkPostBodySchema(properties[property], isRequired);
938
+ paramResult.requiredNum += result.requiredNum;
939
+ paramResult.optionalNum += result.optionalNum;
940
+ paramResult.isValid = paramResult.isValid && result.isValid;
941
+ paramResult.reason.push(...result.reason);
942
+ }
943
+ }
944
+ else {
945
+ if (isRequiredWithoutDefault && !isCopilot) {
946
+ paramResult.isValid = false;
947
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
948
+ }
949
+ }
950
+ return paramResult;
951
+ }
952
+ checkParamSchema(paramObject) {
953
+ const paramResult = {
954
+ requiredNum: 0,
955
+ optionalNum: 0,
956
+ isValid: true,
957
+ reason: [],
958
+ };
959
+ if (!paramObject) {
960
+ return paramResult;
961
+ }
962
+ for (let i = 0; i < paramObject.length; i++) {
963
+ const param = paramObject[i];
964
+ const schema = param.schema;
965
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
966
+ if (param.in === "header" || param.in === "cookie") {
967
+ if (isRequiredWithoutDefault) {
968
+ paramResult.isValid = false;
969
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
970
+ }
971
+ continue;
972
+ }
973
+ if (schema.type !== "boolean" &&
974
+ schema.type !== "string" &&
975
+ schema.type !== "number" &&
976
+ schema.type !== "integer") {
977
+ if (isRequiredWithoutDefault) {
978
+ paramResult.isValid = false;
979
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
980
+ }
981
+ continue;
982
+ }
983
+ if (param.in === "query" || param.in === "path") {
984
+ if (isRequiredWithoutDefault) {
985
+ paramResult.requiredNum = paramResult.requiredNum + 1;
986
+ }
987
+ else {
988
+ paramResult.optionalNum = paramResult.optionalNum + 1;
989
+ }
990
+ }
991
+ }
992
+ return paramResult;
993
+ }
1011
994
  validateParamCount(postBodyResult, paramResult) {
1012
995
  const result = { isValid: true, reason: [] };
1013
996
  const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
@@ -1709,7 +1692,7 @@ function inferProperties(card) {
1709
1692
 
1710
1693
  // Copyright (c) Microsoft Corporation.
1711
1694
  class ManifestUpdater {
1712
- static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authInfo, existingPluginManifestInfo) {
1695
+ static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authMap, existingPluginManifestInfo) {
1713
1696
  const manifest = await fs.readJSON(manifestPath);
1714
1697
  const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
1715
1698
  const useCopilotExtensionsInSchema = await ManifestUtil.useCopilotExtensionsInSchema(manifest);
@@ -1739,7 +1722,7 @@ class ManifestUpdater {
1739
1722
  }
1740
1723
  const appName = this.removeEnvs(manifest.name.short);
1741
1724
  const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
1742
- const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo);
1725
+ const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo);
1743
1726
  return [manifest, apiPlugin, warnings];
1744
1727
  }
1745
1728
  static updateManifestDescription(manifest, spec) {
@@ -1761,28 +1744,13 @@ class ManifestUpdater {
1761
1744
  throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
1762
1745
  }
1763
1746
  }
1764
- static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo) {
1747
+ static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo) {
1765
1748
  var _a, _b, _c, _d;
1766
1749
  const warnings = [];
1767
1750
  const functions = [];
1768
- const functionNames = [];
1751
+ const functionNamesMap = {};
1769
1752
  const conversationStarters = [];
1770
1753
  const paths = spec.paths;
1771
- const pluginAuthObj = {
1772
- type: "None",
1773
- };
1774
- if (authInfo) {
1775
- if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
1776
- pluginAuthObj.type = "OAuthPluginVault";
1777
- }
1778
- else if (Utils.isBearerTokenAuth(authInfo.authScheme)) {
1779
- pluginAuthObj.type = "ApiKeyPluginVault";
1780
- }
1781
- if (pluginAuthObj.type !== "None") {
1782
- const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1783
- pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
1784
- }
1785
- }
1786
1754
  for (const pathUrl in paths) {
1787
1755
  const pathItem = paths[pathUrl];
1788
1756
  if (pathItem) {
@@ -1790,36 +1758,11 @@ class ManifestUpdater {
1790
1758
  for (const method in operations) {
1791
1759
  if (options.allowMethods.includes(method)) {
1792
1760
  const operationItem = operations[method];
1793
- const confirmationBodies = [];
1794
1761
  if (operationItem) {
1795
1762
  const operationId = operationItem.operationId;
1796
1763
  const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
1797
1764
  const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1798
1765
  const summary = operationItem.summary;
1799
- const paramObject = operationItem.parameters;
1800
- const requestBody = operationItem.requestBody;
1801
- if (paramObject) {
1802
- for (let i = 0; i < paramObject.length; i++) {
1803
- const param = paramObject[i];
1804
- const schema = param.schema;
1805
- ManifestUpdater.checkSchema(schema, method, pathUrl);
1806
- confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
1807
- }
1808
- }
1809
- if (requestBody) {
1810
- const requestJsonBody = requestBody.content["application/json"];
1811
- const requestBodySchema = requestJsonBody.schema;
1812
- if (Utils.isObjectSchema(requestBodySchema)) {
1813
- for (const property in requestBodySchema.properties) {
1814
- const schema = requestBodySchema.properties[property];
1815
- ManifestUpdater.checkSchema(schema, method, pathUrl);
1816
- confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
1817
- }
1818
- }
1819
- else {
1820
- throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
1821
- }
1822
- }
1823
1766
  let funcDescription = operationItem.description || operationItem.summary || "";
1824
1767
  if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
1825
1768
  warnings.push({
@@ -1853,19 +1796,66 @@ class ManifestUpdater {
1853
1796
  }
1854
1797
  }
1855
1798
  if (options.allowConfirmation && method !== ConstantString.GetMethod) {
1856
- if (!funcObj.capabilities) {
1857
- funcObj.capabilities = {};
1799
+ const paramObject = operationItem.parameters;
1800
+ const requestBody = operationItem.requestBody;
1801
+ const confirmationBodies = [];
1802
+ if (paramObject) {
1803
+ for (let i = 0; i < paramObject.length; i++) {
1804
+ const param = paramObject[i];
1805
+ const schema = param.schema;
1806
+ ManifestUpdater.checkSchema(schema, method, pathUrl);
1807
+ confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
1808
+ }
1809
+ }
1810
+ if (requestBody) {
1811
+ const requestJsonBody = Utils.getJsonContentType(requestBody);
1812
+ const requestBodySchema = requestJsonBody.schema;
1813
+ if (Utils.isObjectSchema(requestBodySchema)) {
1814
+ for (const property in requestBodySchema.properties) {
1815
+ const schema = requestBodySchema.properties[property];
1816
+ ManifestUpdater.checkSchema(schema, method, pathUrl);
1817
+ confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
1818
+ }
1819
+ }
1820
+ else {
1821
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
1822
+ }
1858
1823
  }
1859
- funcObj.capabilities.confirmation = {
1860
- type: "AdaptiveCard",
1861
- title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
1862
- };
1863
1824
  if (confirmationBodies.length > 0) {
1825
+ if (!funcObj.capabilities) {
1826
+ funcObj.capabilities = {};
1827
+ }
1828
+ funcObj.capabilities.confirmation = {
1829
+ type: "AdaptiveCard",
1830
+ title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
1831
+ };
1864
1832
  funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
1865
1833
  }
1866
1834
  }
1867
1835
  functions.push(funcObj);
1868
- functionNames.push(safeFunctionName);
1836
+ const authInfo = authMap[operationId];
1837
+ let key = "None";
1838
+ let authName = "None";
1839
+ if (authInfo) {
1840
+ if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
1841
+ key = "OAuthPluginVault";
1842
+ authName = authInfo.name;
1843
+ }
1844
+ else if (Utils.isBearerTokenAuth(authInfo.authScheme) ||
1845
+ Utils.isAPIKeyAuthButNotInCookie(authInfo.authScheme)) {
1846
+ key = "ApiKeyPluginVault";
1847
+ authName = authInfo.name;
1848
+ }
1849
+ }
1850
+ if (functionNamesMap[key]) {
1851
+ functionNamesMap[key].functionNames.push(safeFunctionName);
1852
+ }
1853
+ else {
1854
+ functionNamesMap[key] = {
1855
+ functionNames: [safeFunctionName],
1856
+ authName: authName,
1857
+ };
1858
+ }
1869
1859
  const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
1870
1860
  if (conversationStarterStr) {
1871
1861
  conversationStarters.push(conversationStarterStr);
@@ -1875,6 +1865,12 @@ class ManifestUpdater {
1875
1865
  }
1876
1866
  }
1877
1867
  }
1868
+ if (Object.keys(functionNamesMap).length === 0) {
1869
+ functionNamesMap["None"] = {
1870
+ functionNames: [],
1871
+ authName: "None",
1872
+ };
1873
+ }
1878
1874
  let apiPlugin;
1879
1875
  if (await fs.pathExists(apiPluginFilePath)) {
1880
1876
  apiPlugin = await fs.readJSON(apiPluginFilePath);
@@ -1910,24 +1906,35 @@ class ManifestUpdater {
1910
1906
  const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
1911
1907
  apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
1912
1908
  }
1913
- const index = apiPlugin.runtimes.findIndex((runtime) => {
1914
- var _a, _b;
1915
- return runtime.spec.url === specRelativePath &&
1916
- runtime.type === "OpenApi" &&
1917
- ((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === pluginAuthObj.type;
1918
- });
1919
- if (index === -1) {
1920
- apiPlugin.runtimes.push({
1921
- type: "OpenApi",
1922
- auth: pluginAuthObj,
1923
- spec: {
1924
- url: specRelativePath,
1925
- },
1926
- run_for_functions: functionNames,
1909
+ for (const authType in functionNamesMap) {
1910
+ const pluginAuthObj = {
1911
+ type: authType,
1912
+ };
1913
+ const authName = functionNamesMap[authType].authName;
1914
+ if (pluginAuthObj.type !== "None") {
1915
+ const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authName}_${ConstantString.RegistrationIdPostfix}`);
1916
+ pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
1917
+ }
1918
+ const functionNamesInfo = functionNamesMap[authType];
1919
+ const index = apiPlugin.runtimes.findIndex((runtime) => {
1920
+ var _a, _b;
1921
+ return runtime.spec.url === specRelativePath &&
1922
+ runtime.type === "OpenApi" &&
1923
+ ((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === authType;
1927
1924
  });
1928
- }
1929
- else {
1930
- apiPlugin.runtimes[index].run_for_functions = functionNames;
1925
+ if (index === -1) {
1926
+ apiPlugin.runtimes.push({
1927
+ type: "OpenApi",
1928
+ auth: pluginAuthObj,
1929
+ spec: {
1930
+ url: specRelativePath,
1931
+ },
1932
+ run_for_functions: functionNamesInfo.functionNames,
1933
+ });
1934
+ }
1935
+ else {
1936
+ apiPlugin.runtimes[index].run_for_functions = functionNamesInfo.functionNames;
1937
+ }
1931
1938
  }
1932
1939
  if (!apiPlugin.name_for_human) {
1933
1940
  apiPlugin.name_for_human = appName;
@@ -1968,7 +1975,7 @@ class ManifestUpdater {
1968
1975
  };
1969
1976
  if (authInfo) {
1970
1977
  const auth = authInfo.authScheme;
1971
- const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1978
+ const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
1972
1979
  if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1973
1980
  composeExtension.authorization = {
1974
1981
  authType: "apiSecretServiceAuth",
@@ -2111,8 +2118,11 @@ class SpecParser {
2111
2118
  await this.parser.validate(this.spec);
2112
2119
  }
2113
2120
  else {
2121
+ // The following code still hangs for Graph API, support will be added when SwaggerParser is updated.
2122
+ /*
2114
2123
  const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
2115
2124
  await this.parser.validate(clonedUnResolveSpec);
2125
+ */
2116
2126
  }
2117
2127
  }
2118
2128
  catch (e) {
@@ -2269,7 +2279,7 @@ class SpecParser {
2269
2279
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
2270
2280
  }
2271
2281
  const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
2272
- const newSpec = (await this.parser.dereference(clonedUnResolveSpec));
2282
+ const newSpec = await this.deReferenceSpec(clonedUnResolveSpec);
2273
2283
  return [newUnResolvedSpec, newSpec];
2274
2284
  }
2275
2285
  catch (err) {
@@ -2279,6 +2289,10 @@ class SpecParser {
2279
2289
  throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
2280
2290
  }
2281
2291
  }
2292
+ async deReferenceSpec(spec) {
2293
+ const result = await this.parser.dereference(spec);
2294
+ return result;
2295
+ }
2282
2296
  /**
2283
2297
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
2284
2298
  * @param manifestPath A file path of the Teams app manifest file to update.
@@ -2295,7 +2309,6 @@ class SpecParser {
2295
2309
  const newSpecs = await this.getFilteredSpecs(filter, signal);
2296
2310
  const newUnResolvedSpec = newSpecs[0];
2297
2311
  const newSpec = newSpecs[1];
2298
- const authInfo = Utils.getAuthInfo(newSpec);
2299
2312
  const paths = newUnResolvedSpec.paths;
2300
2313
  for (const pathUrl in paths) {
2301
2314
  const operations = paths[pathUrl];
@@ -2303,15 +2316,22 @@ class SpecParser {
2303
2316
  const operationItem = operations[method];
2304
2317
  const operationId = operationItem.operationId;
2305
2318
  const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
2306
- if (!containsSpecialCharacters) {
2307
- continue;
2319
+ if (containsSpecialCharacters) {
2320
+ operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
2321
+ result.warnings.push({
2322
+ type: WarningType.OperationIdContainsSpecialCharacters,
2323
+ content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
2324
+ data: operationId,
2325
+ });
2326
+ }
2327
+ const authArray = Utils.getAuthArray(operationItem.security, newSpec);
2328
+ if (Utils.isNotSupportedAuth(authArray)) {
2329
+ result.warnings.push({
2330
+ type: WarningType.UnsupportedAuthType,
2331
+ content: Utils.format(ConstantString.AuthTypeIsNotSupported, operationId),
2332
+ data: operationId,
2333
+ });
2308
2334
  }
2309
- operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
2310
- result.warnings.push({
2311
- type: WarningType.OperationIdContainsSpecialCharacters,
2312
- content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
2313
- data: operationId,
2314
- });
2315
2335
  }
2316
2336
  }
2317
2337
  await this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
@@ -2324,7 +2344,8 @@ class SpecParser {
2324
2344
  specPath: this.pathOrSpec,
2325
2345
  }
2326
2346
  : undefined;
2327
- const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authInfo, existingPluginManifestInfo);
2347
+ const authMap = Utils.getAuthMap(newSpec);
2348
+ const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authMap, existingPluginManifestInfo);
2328
2349
  result.warnings.push(...warnings);
2329
2350
  await fs.outputJSON(manifestPath, updatedManifest, { spaces: 4 });
2330
2351
  await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
@@ -2401,6 +2422,52 @@ class SpecParser {
2401
2422
  }
2402
2423
  return result;
2403
2424
  }
2425
+ /**
2426
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
2427
+ * @param pluginFilePath A file path of the plugin manifest file to update.
2428
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
2429
+ */
2430
+ async generateAdaptiveCardInPlugin(pluginFilePath, filter, signal) {
2431
+ if (!this.options.allowResponseSemantics) {
2432
+ return;
2433
+ }
2434
+ const newSpecs = await this.getFilteredSpecs(filter, signal);
2435
+ const newSpec = newSpecs[1];
2436
+ const apiPlugin = (await fs.readJSON(pluginFilePath));
2437
+ const paths = newSpec.paths;
2438
+ for (const pathUrl in paths) {
2439
+ const pathItem = paths[pathUrl];
2440
+ if (pathItem) {
2441
+ const operations = pathItem;
2442
+ for (const method in operations) {
2443
+ if (this.options.allowMethods.includes(method)) {
2444
+ const operationItem = operations[method];
2445
+ if (operationItem) {
2446
+ try {
2447
+ const operationId = operationItem.operationId;
2448
+ const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
2449
+ if (apiPlugin.functions.findIndex((func) => func.name === safeFunctionName) === -1) {
2450
+ continue;
2451
+ }
2452
+ const { json } = Utils.getResponseJson(operationItem);
2453
+ if (json.schema) {
2454
+ const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem, false, 5);
2455
+ const responseSemantic = wrapResponseSemantics(card, jsonPath);
2456
+ apiPlugin.functions.find((func) => func.name === safeFunctionName).capabilities = {
2457
+ response_semantics: responseSemantic,
2458
+ };
2459
+ }
2460
+ }
2461
+ catch (err) {
2462
+ throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
2463
+ }
2464
+ }
2465
+ }
2466
+ }
2467
+ }
2468
+ }
2469
+ await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
2470
+ }
2404
2471
  async loadSpec() {
2405
2472
  if (!this.spec) {
2406
2473
  const spec = (await this.parser.parse(this.pathOrSpec));
@@ -2412,7 +2479,7 @@ class SpecParser {
2412
2479
  this.isSwaggerFile = true;
2413
2480
  }
2414
2481
  const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
2415
- this.spec = (await this.parser.dereference(clonedUnResolveSpec));
2482
+ this.spec = await this.deReferenceSpec(clonedUnResolveSpec);
2416
2483
  }
2417
2484
  }
2418
2485
  getAPIs(spec) {