@microsoft/m365-spec-parser 0.2.4 → 0.2.5-alpha.4da5c3b2d.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.
@@ -9,6 +9,7 @@ var fs = require('fs-extra');
9
9
  var path = require('path');
10
10
  var teamsManifest = require('@microsoft/teams-manifest');
11
11
  var crypto = require('crypto');
12
+ var jsonSchemaRefParser = require('@apidevtools/json-schema-ref-parser');
12
13
 
13
14
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
15
 
@@ -80,11 +81,8 @@ exports.ErrorType = void 0;
80
81
  ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
81
82
  ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
82
83
  ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
83
- ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
84
84
  ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
85
85
  ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
86
- ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
87
- ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
88
86
  ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
89
87
  ErrorType["NoParameter"] = "no-parameter";
90
88
  ErrorType["NoAPIInfo"] = "no-api-info";
@@ -104,6 +102,7 @@ exports.WarningType = void 0;
104
102
  WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
105
103
  WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
106
104
  WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
105
+ WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
107
106
  WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
108
107
  WarningType["Unknown"] = "unknown";
109
108
  })(exports.WarningType || (exports.WarningType = {}));
@@ -143,6 +142,7 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
143
142
  ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
144
143
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
145
144
  ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
145
+ ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
146
146
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
147
147
  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.";
148
148
  ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
@@ -152,17 +152,12 @@ ConstantString.WrappedCardResponseLayout = "list";
152
152
  ConstantString.GetMethod = "get";
153
153
  ConstantString.PostMethod = "post";
154
154
  ConstantString.AdaptiveCardVersion = "1.5";
155
- ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
155
+ ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
156
156
  ConstantString.AdaptiveCardType = "AdaptiveCard";
157
157
  ConstantString.TextBlockType = "TextBlock";
158
158
  ConstantString.ImageType = "Image";
159
159
  ConstantString.ContainerType = "Container";
160
- ConstantString.RegistrationIdPostfix = {
161
- apiKey: "REGISTRATION_ID",
162
- oauth2: "CONFIGURATION_ID",
163
- http: "REGISTRATION_ID",
164
- openIdConnect: "REGISTRATION_ID",
165
- };
160
+ ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
166
161
  ConstantString.ResponseCodeFor20X = [
167
162
  "200",
168
163
  "201",
@@ -174,6 +169,7 @@ ConstantString.ResponseCodeFor20X = [
174
169
  "207",
175
170
  "208",
176
171
  "226",
172
+ "2XX",
177
173
  "default",
178
174
  ];
179
175
  ConstantString.AllOperationMethods = [
@@ -239,17 +235,6 @@ class SpecParserError extends Error {
239
235
 
240
236
  // Copyright (c) Microsoft Corporation.
241
237
  class Utils {
242
- static hasNestedObjectInSchema(schema) {
243
- if (this.isObjectSchema(schema)) {
244
- for (const property in schema.properties) {
245
- const nestedSchema = schema.properties[property];
246
- if (this.isObjectSchema(nestedSchema)) {
247
- return true;
248
- }
249
- }
250
- }
251
- return false;
252
- }
253
238
  static isObjectSchema(schema) {
254
239
  return schema.type === "object" || (!schema.type && !!schema.properties);
255
240
  }
@@ -262,11 +247,32 @@ class Utils {
262
247
  static isAPIKeyAuth(authScheme) {
263
248
  return authScheme.type === "apiKey";
264
249
  }
250
+ static isAPIKeyAuthButNotInCookie(authScheme) {
251
+ return authScheme.type === "apiKey" && authScheme.in !== "cookie";
252
+ }
265
253
  static isOAuthWithAuthCodeFlow(authScheme) {
266
254
  return !!(authScheme.type === "oauth2" &&
267
255
  authScheme.flows &&
268
256
  authScheme.flows.authorizationCode);
269
257
  }
258
+ static isNotSupportedAuth(authSchemeArray) {
259
+ if (authSchemeArray.length === 0) {
260
+ return false;
261
+ }
262
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
263
+ return true;
264
+ }
265
+ for (const auths of authSchemeArray) {
266
+ if (auths.length === 1) {
267
+ if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
268
+ Utils.isBearerTokenAuth(auths[0].authScheme) ||
269
+ Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
270
+ return false;
271
+ }
272
+ }
273
+ }
274
+ return true;
275
+ }
270
276
  static getAuthArray(securities, spec) {
271
277
  var _a;
272
278
  const result = [];
@@ -291,6 +297,20 @@ class Utils {
291
297
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
292
298
  return result;
293
299
  }
300
+ static getAuthMap(spec) {
301
+ const authMap = {};
302
+ for (const url in spec.paths) {
303
+ for (const method in spec.paths[url]) {
304
+ const operation = spec.paths[url][method];
305
+ const authArray = Utils.getAuthArray(operation.security, spec);
306
+ if (authArray && authArray.length > 0) {
307
+ const currentAuth = authArray[0][0];
308
+ authMap[operation.operationId] = currentAuth;
309
+ }
310
+ }
311
+ }
312
+ return authMap;
313
+ }
294
314
  static getAuthInfo(spec) {
295
315
  let authInfo = undefined;
296
316
  for (const url in spec.paths) {
@@ -319,27 +339,33 @@ class Utils {
319
339
  let multipleMediaType = false;
320
340
  for (const code of ConstantString.ResponseCodeFor20X) {
321
341
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
322
- if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
323
- for (const contentType of Object.keys(responseObject.content)) {
324
- // json media type can also be "application/json; charset=utf-8"
325
- if (contentType.indexOf("application/json") >= 0) {
326
- multipleMediaType = false;
327
- json = responseObject.content[contentType];
328
- if (Utils.containMultipleMediaTypes(responseObject)) {
329
- multipleMediaType = true;
330
- if (!allowMultipleMediaType) {
331
- json = {};
332
- }
333
- }
334
- else {
335
- return { json, multipleMediaType };
336
- }
337
- }
338
- }
342
+ if (!responseObject) {
343
+ continue;
344
+ }
345
+ multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
346
+ if (!allowMultipleMediaType && multipleMediaType) {
347
+ json = {};
348
+ continue;
349
+ }
350
+ const mediaObj = Utils.getJsonContentType(responseObject);
351
+ if (Object.keys(mediaObj).length > 0) {
352
+ json = mediaObj;
353
+ return { json, multipleMediaType };
339
354
  }
340
355
  }
341
356
  return { json, multipleMediaType };
342
357
  }
358
+ static getJsonContentType(responseObject) {
359
+ if (responseObject.content) {
360
+ for (const contentType of Object.keys(responseObject.content)) {
361
+ // json media type can also be "application/json; charset=utf-8"
362
+ if (contentType.indexOf("application/json") >= 0) {
363
+ return responseObject.content[contentType];
364
+ }
365
+ }
366
+ }
367
+ return {};
368
+ }
343
369
  static convertPathToCamelCase(path) {
344
370
  const pathSegments = path.split(/[./{]/);
345
371
  const camelCaseSegments = pathSegments.map((segment) => {
@@ -375,7 +401,7 @@ class Utils {
375
401
  }
376
402
  return newStr;
377
403
  }
378
- static checkServerUrl(servers) {
404
+ static checkServerUrl(servers, allowHttp = false) {
379
405
  const errors = [];
380
406
  let serverUrl;
381
407
  try {
@@ -398,8 +424,7 @@ class Utils {
398
424
  data: servers,
399
425
  });
400
426
  }
401
- else if (protocol !== "https:") {
402
- // Http server url is not supported
427
+ else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
403
428
  const protocolString = protocol.slice(0, -1);
404
429
  errors.push({
405
430
  type: exports.ErrorType.UrlProtocolNotSupported,
@@ -415,10 +440,11 @@ class Utils {
415
440
  let hasTopLevelServers = false;
416
441
  let hasPathLevelServers = false;
417
442
  let hasOperationLevelServers = false;
443
+ const allowHttp = options.projectType === exports.ProjectType.Copilot;
418
444
  if (spec.servers && spec.servers.length >= 1) {
419
445
  hasTopLevelServers = true;
420
446
  // for multiple server, we only use the first url
421
- const serverErrors = Utils.checkServerUrl(spec.servers);
447
+ const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
422
448
  errors.push(...serverErrors);
423
449
  }
424
450
  const paths = spec.paths;
@@ -426,7 +452,7 @@ class Utils {
426
452
  const methods = paths[path];
427
453
  if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
428
454
  hasPathLevelServers = true;
429
- const serverErrors = Utils.checkServerUrl(methods.servers);
455
+ const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
430
456
  errors.push(...serverErrors);
431
457
  }
432
458
  for (const method in methods) {
@@ -434,7 +460,7 @@ class Utils {
434
460
  if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
435
461
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
436
462
  hasOperationLevelServers = true;
437
- const serverErrors = Utils.checkServerUrl(operationObject.servers);
463
+ const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
438
464
  errors.push(...serverErrors);
439
465
  }
440
466
  }
@@ -723,22 +749,6 @@ class Validator {
723
749
  }
724
750
  return result;
725
751
  }
726
- validateResponse(method, path) {
727
- const result = { isValid: true, reason: [] };
728
- const operationObject = this.spec.paths[path][method];
729
- const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
730
- if (this.options.projectType === exports.ProjectType.SME) {
731
- // only support response body only contains “application/json” content type
732
- if (multipleMediaType) {
733
- result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
734
- }
735
- else if (Object.keys(json).length === 0) {
736
- // response body should not be empty
737
- result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
738
- }
739
- }
740
- return result;
741
- }
742
752
  validateServer(method, path) {
743
753
  const result = { isValid: true, reason: [] };
744
754
  const serverObj = Utils.getServerObject(this.spec, method, path);
@@ -747,8 +757,8 @@ class Validator {
747
757
  result.reason.push(exports.ErrorType.NoServerInformation);
748
758
  }
749
759
  else {
750
- // server url should be absolute url with https protocol
751
- const serverValidateResult = Utils.checkServerUrl([serverObj]);
760
+ const allowHttp = this.projectType === exports.ProjectType.Copilot;
761
+ const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
752
762
  result.reason.push(...serverValidateResult.map((item) => item.type));
753
763
  }
754
764
  return result;
@@ -771,6 +781,9 @@ class Validator {
771
781
  reason: [exports.ErrorType.MultipleAuthNotSupported],
772
782
  };
773
783
  }
784
+ if (this.projectType === exports.ProjectType.Copilot) {
785
+ return { isValid: true, reason: [] };
786
+ }
774
787
  for (const auths of authSchemeArray) {
775
788
  if (auths.length === 1) {
776
789
  if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
@@ -783,114 +796,6 @@ class Validator {
783
796
  }
784
797
  return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
785
798
  }
786
- checkPostBodySchema(schema, isRequired = false) {
787
- var _a;
788
- const paramResult = {
789
- requiredNum: 0,
790
- optionalNum: 0,
791
- isValid: true,
792
- reason: [],
793
- };
794
- if (Object.keys(schema).length === 0) {
795
- return paramResult;
796
- }
797
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
798
- const isCopilot = this.projectType === exports.ProjectType.Copilot;
799
- if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
800
- paramResult.isValid = false;
801
- paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
802
- return paramResult;
803
- }
804
- if (schema.type === "string" ||
805
- schema.type === "integer" ||
806
- schema.type === "boolean" ||
807
- schema.type === "number") {
808
- if (isRequiredWithoutDefault) {
809
- paramResult.requiredNum = paramResult.requiredNum + 1;
810
- }
811
- else {
812
- paramResult.optionalNum = paramResult.optionalNum + 1;
813
- }
814
- }
815
- else if (Utils.isObjectSchema(schema)) {
816
- const { properties } = schema;
817
- for (const property in properties) {
818
- let isRequired = false;
819
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
820
- isRequired = true;
821
- }
822
- const result = this.checkPostBodySchema(properties[property], isRequired);
823
- paramResult.requiredNum += result.requiredNum;
824
- paramResult.optionalNum += result.optionalNum;
825
- paramResult.isValid = paramResult.isValid && result.isValid;
826
- paramResult.reason.push(...result.reason);
827
- }
828
- }
829
- else {
830
- if (isRequiredWithoutDefault && !isCopilot) {
831
- paramResult.isValid = false;
832
- paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
833
- }
834
- }
835
- return paramResult;
836
- }
837
- checkParamSchema(paramObject) {
838
- const paramResult = {
839
- requiredNum: 0,
840
- optionalNum: 0,
841
- isValid: true,
842
- reason: [],
843
- };
844
- if (!paramObject) {
845
- return paramResult;
846
- }
847
- const isCopilot = this.projectType === exports.ProjectType.Copilot;
848
- for (let i = 0; i < paramObject.length; i++) {
849
- const param = paramObject[i];
850
- const schema = param.schema;
851
- if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
852
- paramResult.isValid = false;
853
- paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
854
- continue;
855
- }
856
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
857
- if (isCopilot) {
858
- if (isRequiredWithoutDefault) {
859
- paramResult.requiredNum = paramResult.requiredNum + 1;
860
- }
861
- else {
862
- paramResult.optionalNum = paramResult.optionalNum + 1;
863
- }
864
- continue;
865
- }
866
- if (param.in === "header" || param.in === "cookie") {
867
- if (isRequiredWithoutDefault) {
868
- paramResult.isValid = false;
869
- paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
870
- }
871
- continue;
872
- }
873
- if (schema.type !== "boolean" &&
874
- schema.type !== "string" &&
875
- schema.type !== "number" &&
876
- schema.type !== "integer") {
877
- if (isRequiredWithoutDefault) {
878
- paramResult.isValid = false;
879
- paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
880
- }
881
- continue;
882
- }
883
- if (param.in === "query" || param.in === "path") {
884
- if (isRequiredWithoutDefault) {
885
- paramResult.requiredNum = paramResult.requiredNum + 1;
886
- }
887
- else {
888
- paramResult.optionalNum = paramResult.optionalNum + 1;
889
- }
890
- }
891
- }
892
- return paramResult;
893
- }
894
799
  }
895
800
 
896
801
  // Copyright (c) Microsoft Corporation.
@@ -900,7 +805,6 @@ class CopilotValidator extends Validator {
900
805
  this.projectType = exports.ProjectType.Copilot;
901
806
  this.options = options;
902
807
  this.spec = spec;
903
- this.checkCircularReference();
904
808
  }
905
809
  validateSpec() {
906
810
  const result = { errors: [], warnings: [] };
@@ -926,10 +830,6 @@ class CopilotValidator extends Validator {
926
830
  if (!methodAndPathResult.isValid) {
927
831
  return methodAndPathResult;
928
832
  }
929
- const circularReferenceResult = this.validateCircularReference(method, path);
930
- if (!circularReferenceResult.isValid) {
931
- return circularReferenceResult;
932
- }
933
833
  const operationObject = this.spec.paths[path][method];
934
834
  // validate auth
935
835
  const authCheckResult = this.validateAuth(method, path);
@@ -941,24 +841,6 @@ class CopilotValidator extends Validator {
941
841
  // validate server
942
842
  const validateServerResult = this.validateServer(method, path);
943
843
  result.reason.push(...validateServerResult.reason);
944
- // validate response
945
- const validateResponseResult = this.validateResponse(method, path);
946
- result.reason.push(...validateResponseResult.reason);
947
- // validate requestBody
948
- const requestBody = operationObject.requestBody;
949
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
950
- if (requestJsonBody) {
951
- const requestBodySchema = requestJsonBody.schema;
952
- if (!Utils.isObjectSchema(requestBodySchema)) {
953
- result.reason.push(exports.ErrorType.PostBodySchemaIsNotJson);
954
- }
955
- const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
956
- result.reason.push(...requestBodyParamResult.reason);
957
- }
958
- // validate parameters
959
- const paramObject = operationObject.parameters;
960
- const paramResult = this.checkParamSchema(paramObject);
961
- result.reason.push(...paramResult.reason);
962
844
  if (result.reason.length > 0) {
963
845
  result.isValid = false;
964
846
  }
@@ -1050,6 +932,108 @@ class SMEValidator extends Validator {
1050
932
  }
1051
933
  return result;
1052
934
  }
935
+ validateResponse(method, path) {
936
+ const result = { isValid: true, reason: [] };
937
+ const operationObject = this.spec.paths[path][method];
938
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
939
+ // only support response body only contains “application/json” content type
940
+ if (multipleMediaType) {
941
+ result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
942
+ }
943
+ else if (Object.keys(json).length === 0) {
944
+ // response body should not be empty
945
+ result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
946
+ }
947
+ return result;
948
+ }
949
+ checkPostBodySchema(schema, isRequired = false) {
950
+ var _a;
951
+ const paramResult = {
952
+ requiredNum: 0,
953
+ optionalNum: 0,
954
+ isValid: true,
955
+ reason: [],
956
+ };
957
+ if (Object.keys(schema).length === 0) {
958
+ return paramResult;
959
+ }
960
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
961
+ const isCopilot = this.projectType === exports.ProjectType.Copilot;
962
+ if (schema.type === "string" ||
963
+ schema.type === "integer" ||
964
+ schema.type === "boolean" ||
965
+ schema.type === "number") {
966
+ if (isRequiredWithoutDefault) {
967
+ paramResult.requiredNum = paramResult.requiredNum + 1;
968
+ }
969
+ else {
970
+ paramResult.optionalNum = paramResult.optionalNum + 1;
971
+ }
972
+ }
973
+ else if (Utils.isObjectSchema(schema)) {
974
+ const { properties } = schema;
975
+ for (const property in properties) {
976
+ let isRequired = false;
977
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
978
+ isRequired = true;
979
+ }
980
+ const result = this.checkPostBodySchema(properties[property], isRequired);
981
+ paramResult.requiredNum += result.requiredNum;
982
+ paramResult.optionalNum += result.optionalNum;
983
+ paramResult.isValid = paramResult.isValid && result.isValid;
984
+ paramResult.reason.push(...result.reason);
985
+ }
986
+ }
987
+ else {
988
+ if (isRequiredWithoutDefault && !isCopilot) {
989
+ paramResult.isValid = false;
990
+ paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
991
+ }
992
+ }
993
+ return paramResult;
994
+ }
995
+ checkParamSchema(paramObject) {
996
+ const paramResult = {
997
+ requiredNum: 0,
998
+ optionalNum: 0,
999
+ isValid: true,
1000
+ reason: [],
1001
+ };
1002
+ if (!paramObject) {
1003
+ return paramResult;
1004
+ }
1005
+ for (let i = 0; i < paramObject.length; i++) {
1006
+ const param = paramObject[i];
1007
+ const schema = param.schema;
1008
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
1009
+ if (param.in === "header" || param.in === "cookie") {
1010
+ if (isRequiredWithoutDefault) {
1011
+ paramResult.isValid = false;
1012
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
1013
+ }
1014
+ continue;
1015
+ }
1016
+ if (schema.type !== "boolean" &&
1017
+ schema.type !== "string" &&
1018
+ schema.type !== "number" &&
1019
+ schema.type !== "integer") {
1020
+ if (isRequiredWithoutDefault) {
1021
+ paramResult.isValid = false;
1022
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
1023
+ }
1024
+ continue;
1025
+ }
1026
+ if (param.in === "query" || param.in === "path") {
1027
+ if (isRequiredWithoutDefault) {
1028
+ paramResult.requiredNum = paramResult.requiredNum + 1;
1029
+ }
1030
+ else {
1031
+ paramResult.optionalNum = paramResult.optionalNum + 1;
1032
+ }
1033
+ }
1034
+ }
1035
+ return paramResult;
1036
+ }
1053
1037
  validateParamCount(postBodyResult, paramResult) {
1054
1038
  const result = { isValid: true, reason: [] };
1055
1039
  const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
@@ -1751,7 +1735,7 @@ function inferProperties(card) {
1751
1735
 
1752
1736
  // Copyright (c) Microsoft Corporation.
1753
1737
  class ManifestUpdater {
1754
- static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authInfo, existingPluginManifestInfo) {
1738
+ static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authMap, existingPluginManifestInfo) {
1755
1739
  return __awaiter(this, void 0, void 0, function* () {
1756
1740
  const manifest = yield fs__default['default'].readJSON(manifestPath);
1757
1741
  const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
@@ -1782,7 +1766,7 @@ class ManifestUpdater {
1782
1766
  }
1783
1767
  const appName = this.removeEnvs(manifest.name.short);
1784
1768
  const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
1785
- const [apiPlugin, warnings] = yield ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo);
1769
+ const [apiPlugin, warnings] = yield ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo);
1786
1770
  return [manifest, apiPlugin, warnings];
1787
1771
  });
1788
1772
  }
@@ -1805,29 +1789,14 @@ class ManifestUpdater {
1805
1789
  throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), exports.ErrorType.UpdateManifestFailed);
1806
1790
  }
1807
1791
  }
1808
- static generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo) {
1792
+ static generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo) {
1809
1793
  var _a, _b, _c, _d;
1810
1794
  return __awaiter(this, void 0, void 0, function* () {
1811
1795
  const warnings = [];
1812
1796
  const functions = [];
1813
- const functionNames = [];
1797
+ const functionNamesMap = {};
1814
1798
  const conversationStarters = [];
1815
1799
  const paths = spec.paths;
1816
- const pluginAuthObj = {
1817
- type: "None",
1818
- };
1819
- if (authInfo) {
1820
- if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
1821
- pluginAuthObj.type = "OAuthPluginVault";
1822
- }
1823
- else if (Utils.isBearerTokenAuth(authInfo.authScheme)) {
1824
- pluginAuthObj.type = "ApiKeyPluginVault";
1825
- }
1826
- if (pluginAuthObj.type !== "None") {
1827
- const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1828
- pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
1829
- }
1830
- }
1831
1800
  for (const pathUrl in paths) {
1832
1801
  const pathItem = paths[pathUrl];
1833
1802
  if (pathItem) {
@@ -1835,36 +1804,11 @@ class ManifestUpdater {
1835
1804
  for (const method in operations) {
1836
1805
  if (options.allowMethods.includes(method)) {
1837
1806
  const operationItem = operations[method];
1838
- const confirmationBodies = [];
1839
1807
  if (operationItem) {
1840
1808
  const operationId = operationItem.operationId;
1841
1809
  const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
1842
1810
  const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1843
1811
  const summary = operationItem.summary;
1844
- const paramObject = operationItem.parameters;
1845
- const requestBody = operationItem.requestBody;
1846
- if (paramObject) {
1847
- for (let i = 0; i < paramObject.length; i++) {
1848
- const param = paramObject[i];
1849
- const schema = param.schema;
1850
- ManifestUpdater.checkSchema(schema, method, pathUrl);
1851
- confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
1852
- }
1853
- }
1854
- if (requestBody) {
1855
- const requestJsonBody = requestBody.content["application/json"];
1856
- const requestBodySchema = requestJsonBody.schema;
1857
- if (Utils.isObjectSchema(requestBodySchema)) {
1858
- for (const property in requestBodySchema.properties) {
1859
- const schema = requestBodySchema.properties[property];
1860
- ManifestUpdater.checkSchema(schema, method, pathUrl);
1861
- confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
1862
- }
1863
- }
1864
- else {
1865
- throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
1866
- }
1867
- }
1868
1812
  let funcDescription = operationItem.description || operationItem.summary || "";
1869
1813
  if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
1870
1814
  warnings.push({
@@ -1898,19 +1842,66 @@ class ManifestUpdater {
1898
1842
  }
1899
1843
  }
1900
1844
  if (options.allowConfirmation && method !== ConstantString.GetMethod) {
1901
- if (!funcObj.capabilities) {
1902
- funcObj.capabilities = {};
1845
+ const paramObject = operationItem.parameters;
1846
+ const requestBody = operationItem.requestBody;
1847
+ const confirmationBodies = [];
1848
+ if (paramObject) {
1849
+ for (let i = 0; i < paramObject.length; i++) {
1850
+ const param = paramObject[i];
1851
+ const schema = param.schema;
1852
+ ManifestUpdater.checkSchema(schema, method, pathUrl);
1853
+ confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
1854
+ }
1855
+ }
1856
+ if (requestBody) {
1857
+ const requestJsonBody = Utils.getJsonContentType(requestBody);
1858
+ const requestBodySchema = requestJsonBody.schema;
1859
+ if (Utils.isObjectSchema(requestBodySchema)) {
1860
+ for (const property in requestBodySchema.properties) {
1861
+ const schema = requestBodySchema.properties[property];
1862
+ ManifestUpdater.checkSchema(schema, method, pathUrl);
1863
+ confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
1864
+ }
1865
+ }
1866
+ else {
1867
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
1868
+ }
1903
1869
  }
1904
- funcObj.capabilities.confirmation = {
1905
- type: "AdaptiveCard",
1906
- title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
1907
- };
1908
1870
  if (confirmationBodies.length > 0) {
1871
+ if (!funcObj.capabilities) {
1872
+ funcObj.capabilities = {};
1873
+ }
1874
+ funcObj.capabilities.confirmation = {
1875
+ type: "AdaptiveCard",
1876
+ title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
1877
+ };
1909
1878
  funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
1910
1879
  }
1911
1880
  }
1912
1881
  functions.push(funcObj);
1913
- functionNames.push(safeFunctionName);
1882
+ const authInfo = authMap[operationId];
1883
+ let key = "None";
1884
+ let authName = "None";
1885
+ if (authInfo) {
1886
+ if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
1887
+ key = "OAuthPluginVault";
1888
+ authName = authInfo.name;
1889
+ }
1890
+ else if (Utils.isBearerTokenAuth(authInfo.authScheme) ||
1891
+ Utils.isAPIKeyAuthButNotInCookie(authInfo.authScheme)) {
1892
+ key = "ApiKeyPluginVault";
1893
+ authName = authInfo.name;
1894
+ }
1895
+ }
1896
+ if (functionNamesMap[key]) {
1897
+ functionNamesMap[key].functionNames.push(safeFunctionName);
1898
+ }
1899
+ else {
1900
+ functionNamesMap[key] = {
1901
+ functionNames: [safeFunctionName],
1902
+ authName: authName,
1903
+ };
1904
+ }
1914
1905
  const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
1915
1906
  if (conversationStarterStr) {
1916
1907
  conversationStarters.push(conversationStarterStr);
@@ -1920,6 +1911,12 @@ class ManifestUpdater {
1920
1911
  }
1921
1912
  }
1922
1913
  }
1914
+ if (Object.keys(functionNamesMap).length === 0) {
1915
+ functionNamesMap["None"] = {
1916
+ functionNames: [],
1917
+ authName: "None",
1918
+ };
1919
+ }
1923
1920
  let apiPlugin;
1924
1921
  if (yield fs__default['default'].pathExists(apiPluginFilePath)) {
1925
1922
  apiPlugin = yield fs__default['default'].readJSON(apiPluginFilePath);
@@ -1955,24 +1952,35 @@ class ManifestUpdater {
1955
1952
  const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
1956
1953
  apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
1957
1954
  }
1958
- const index = apiPlugin.runtimes.findIndex((runtime) => {
1959
- var _a, _b;
1960
- return runtime.spec.url === specRelativePath &&
1961
- runtime.type === "OpenApi" &&
1962
- ((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === pluginAuthObj.type;
1963
- });
1964
- if (index === -1) {
1965
- apiPlugin.runtimes.push({
1966
- type: "OpenApi",
1967
- auth: pluginAuthObj,
1968
- spec: {
1969
- url: specRelativePath,
1970
- },
1971
- run_for_functions: functionNames,
1955
+ for (const authType in functionNamesMap) {
1956
+ const pluginAuthObj = {
1957
+ type: authType,
1958
+ };
1959
+ const authName = functionNamesMap[authType].authName;
1960
+ if (pluginAuthObj.type !== "None") {
1961
+ const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authName}_${ConstantString.RegistrationIdPostfix}`);
1962
+ pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
1963
+ }
1964
+ const functionNamesInfo = functionNamesMap[authType];
1965
+ const index = apiPlugin.runtimes.findIndex((runtime) => {
1966
+ var _a, _b;
1967
+ return runtime.spec.url === specRelativePath &&
1968
+ runtime.type === "OpenApi" &&
1969
+ ((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === authType;
1972
1970
  });
1973
- }
1974
- else {
1975
- apiPlugin.runtimes[index].run_for_functions = functionNames;
1971
+ if (index === -1) {
1972
+ apiPlugin.runtimes.push({
1973
+ type: "OpenApi",
1974
+ auth: pluginAuthObj,
1975
+ spec: {
1976
+ url: specRelativePath,
1977
+ },
1978
+ run_for_functions: functionNamesInfo.functionNames,
1979
+ });
1980
+ }
1981
+ else {
1982
+ apiPlugin.runtimes[index].run_for_functions = functionNamesInfo.functionNames;
1983
+ }
1976
1984
  }
1977
1985
  if (!apiPlugin.name_for_human) {
1978
1986
  apiPlugin.name_for_human = appName;
@@ -2015,7 +2023,7 @@ class ManifestUpdater {
2015
2023
  };
2016
2024
  if (authInfo) {
2017
2025
  const auth = authInfo.authScheme;
2018
- const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
2026
+ const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
2019
2027
  if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
2020
2028
  composeExtension.authorization = {
2021
2029
  authType: "apiSecretServiceAuth",
@@ -2145,6 +2153,7 @@ class SpecParser {
2145
2153
  };
2146
2154
  this.pathOrSpec = pathOrDoc;
2147
2155
  this.parser = new SwaggerParser__default['default']();
2156
+ this.refParser = new jsonSchemaRefParser.$RefParser();
2148
2157
  this.options = Object.assign(Object.assign({}, this.defaultOptions), (options !== null && options !== void 0 ? options : {}));
2149
2158
  }
2150
2159
  /**
@@ -2158,12 +2167,15 @@ class SpecParser {
2158
2167
  let hash = "";
2159
2168
  try {
2160
2169
  yield this.loadSpec();
2161
- if (!this.parser.$refs.circular) {
2170
+ if (!this.refParser.$refs.circular) {
2162
2171
  yield this.parser.validate(this.spec);
2163
2172
  }
2164
2173
  else {
2174
+ // The following code hangs for Graph API, support will be added when SwaggerParser is updated.
2175
+ /*
2165
2176
  const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
2166
- yield this.parser.validate(clonedUnResolveSpec);
2177
+ await this.parser.validate(clonedUnResolveSpec);
2178
+ */
2167
2179
  }
2168
2180
  }
2169
2181
  catch (e) {
@@ -2191,7 +2203,7 @@ class SpecParser {
2191
2203
  };
2192
2204
  }
2193
2205
  // Remote reference not supported
2194
- const refPaths = this.parser.$refs.paths();
2206
+ const refPaths = this.refParser.$refs.paths();
2195
2207
  // refPaths [0] is the current spec file path
2196
2208
  if (refPaths.length > 1) {
2197
2209
  errors.push({
@@ -2326,7 +2338,7 @@ class SpecParser {
2326
2338
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
2327
2339
  }
2328
2340
  const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
2329
- const newSpec = (yield this.parser.dereference(clonedUnResolveSpec));
2341
+ const newSpec = yield this.deReferenceSpec(clonedUnResolveSpec);
2330
2342
  return [newUnResolvedSpec, newSpec];
2331
2343
  }
2332
2344
  catch (err) {
@@ -2337,6 +2349,12 @@ class SpecParser {
2337
2349
  }
2338
2350
  });
2339
2351
  }
2352
+ deReferenceSpec(spec) {
2353
+ return __awaiter(this, void 0, void 0, function* () {
2354
+ const result = yield this.refParser.dereference(spec);
2355
+ return result;
2356
+ });
2357
+ }
2340
2358
  /**
2341
2359
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
2342
2360
  * @param manifestPath A file path of the Teams app manifest file to update.
@@ -2354,7 +2372,6 @@ class SpecParser {
2354
2372
  const newSpecs = yield this.getFilteredSpecs(filter, signal);
2355
2373
  const newUnResolvedSpec = newSpecs[0];
2356
2374
  const newSpec = newSpecs[1];
2357
- const authInfo = Utils.getAuthInfo(newSpec);
2358
2375
  const paths = newUnResolvedSpec.paths;
2359
2376
  for (const pathUrl in paths) {
2360
2377
  const operations = paths[pathUrl];
@@ -2362,15 +2379,22 @@ class SpecParser {
2362
2379
  const operationItem = operations[method];
2363
2380
  const operationId = operationItem.operationId;
2364
2381
  const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
2365
- if (!containsSpecialCharacters) {
2366
- continue;
2382
+ if (containsSpecialCharacters) {
2383
+ operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
2384
+ result.warnings.push({
2385
+ type: exports.WarningType.OperationIdContainsSpecialCharacters,
2386
+ content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
2387
+ data: operationId,
2388
+ });
2389
+ }
2390
+ const authArray = Utils.getAuthArray(operationItem.security, newSpec);
2391
+ if (Utils.isNotSupportedAuth(authArray)) {
2392
+ result.warnings.push({
2393
+ type: exports.WarningType.UnsupportedAuthType,
2394
+ content: Utils.format(ConstantString.AuthTypeIsNotSupported, operationId),
2395
+ data: operationId,
2396
+ });
2367
2397
  }
2368
- operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
2369
- result.warnings.push({
2370
- type: exports.WarningType.OperationIdContainsSpecialCharacters,
2371
- content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
2372
- data: operationId,
2373
- });
2374
2398
  }
2375
2399
  }
2376
2400
  yield this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
@@ -2383,7 +2407,8 @@ class SpecParser {
2383
2407
  specPath: this.pathOrSpec,
2384
2408
  }
2385
2409
  : undefined;
2386
- const [updatedManifest, apiPlugin, warnings] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authInfo, existingPluginManifestInfo);
2410
+ const authMap = Utils.getAuthMap(newSpec);
2411
+ const [updatedManifest, apiPlugin, warnings] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authMap, existingPluginManifestInfo);
2387
2412
  result.warnings.push(...warnings);
2388
2413
  yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 4 });
2389
2414
  yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
@@ -2475,7 +2500,7 @@ class SpecParser {
2475
2500
  this.isSwaggerFile = true;
2476
2501
  }
2477
2502
  const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
2478
- this.spec = (yield this.parser.dereference(clonedUnResolveSpec));
2503
+ this.spec = yield this.deReferenceSpec(clonedUnResolveSpec);
2479
2504
  }
2480
2505
  });
2481
2506
  }