@microsoft/m365-spec-parser 0.2.4-rc.0 → 0.2.4

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,7 +9,6 @@ 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');
13
12
 
14
13
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
15
14
 
@@ -81,8 +80,11 @@ exports.ErrorType = void 0;
81
80
  ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
82
81
  ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
83
82
  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";
86
88
  ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
87
89
  ErrorType["NoParameter"] = "no-parameter";
88
90
  ErrorType["NoAPIInfo"] = "no-api-info";
@@ -102,7 +104,6 @@ exports.WarningType = void 0;
102
104
  WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
103
105
  WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
104
106
  WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
105
- WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
106
107
  WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
107
108
  WarningType["Unknown"] = "unknown";
108
109
  })(exports.WarningType || (exports.WarningType = {}));
@@ -142,7 +143,6 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
142
143
  ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
143
144
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
144
145
  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,12 +152,17 @@ ConstantString.WrappedCardResponseLayout = "list";
152
152
  ConstantString.GetMethod = "get";
153
153
  ConstantString.PostMethod = "post";
154
154
  ConstantString.AdaptiveCardVersion = "1.5";
155
- ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
155
+ ConstantString.AdaptiveCardSchema = "http://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 = "REGISTRATION_ID";
160
+ ConstantString.RegistrationIdPostfix = {
161
+ apiKey: "REGISTRATION_ID",
162
+ oauth2: "CONFIGURATION_ID",
163
+ http: "REGISTRATION_ID",
164
+ openIdConnect: "REGISTRATION_ID",
165
+ };
161
166
  ConstantString.ResponseCodeFor20X = [
162
167
  "200",
163
168
  "201",
@@ -169,7 +174,6 @@ ConstantString.ResponseCodeFor20X = [
169
174
  "207",
170
175
  "208",
171
176
  "226",
172
- "2XX",
173
177
  "default",
174
178
  ];
175
179
  ConstantString.AllOperationMethods = [
@@ -235,6 +239,17 @@ class SpecParserError extends Error {
235
239
 
236
240
  // Copyright (c) Microsoft Corporation.
237
241
  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
+ }
238
253
  static isObjectSchema(schema) {
239
254
  return schema.type === "object" || (!schema.type && !!schema.properties);
240
255
  }
@@ -247,32 +262,11 @@ class Utils {
247
262
  static isAPIKeyAuth(authScheme) {
248
263
  return authScheme.type === "apiKey";
249
264
  }
250
- static isAPIKeyAuthButNotInCookie(authScheme) {
251
- return authScheme.type === "apiKey" && authScheme.in !== "cookie";
252
- }
253
265
  static isOAuthWithAuthCodeFlow(authScheme) {
254
266
  return !!(authScheme.type === "oauth2" &&
255
267
  authScheme.flows &&
256
268
  authScheme.flows.authorizationCode);
257
269
  }
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
- }
276
270
  static getAuthArray(securities, spec) {
277
271
  var _a;
278
272
  const result = [];
@@ -297,20 +291,6 @@ class Utils {
297
291
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
298
292
  return result;
299
293
  }
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
- }
314
294
  static getAuthInfo(spec) {
315
295
  let authInfo = undefined;
316
296
  for (const url in spec.paths) {
@@ -339,32 +319,26 @@ class Utils {
339
319
  let multipleMediaType = false;
340
320
  for (const code of ConstantString.ResponseCodeFor20X) {
341
321
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
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 };
354
- }
355
- }
356
- return { json, multipleMediaType };
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];
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
+ }
364
338
  }
365
339
  }
366
340
  }
367
- return {};
341
+ return { json, multipleMediaType };
368
342
  }
369
343
  static convertPathToCamelCase(path) {
370
344
  const pathSegments = path.split(/[./{]/);
@@ -401,7 +375,7 @@ class Utils {
401
375
  }
402
376
  return newStr;
403
377
  }
404
- static checkServerUrl(servers, allowHttp = false) {
378
+ static checkServerUrl(servers) {
405
379
  const errors = [];
406
380
  let serverUrl;
407
381
  try {
@@ -424,7 +398,8 @@ class Utils {
424
398
  data: servers,
425
399
  });
426
400
  }
427
- else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
401
+ else if (protocol !== "https:") {
402
+ // Http server url is not supported
428
403
  const protocolString = protocol.slice(0, -1);
429
404
  errors.push({
430
405
  type: exports.ErrorType.UrlProtocolNotSupported,
@@ -440,11 +415,10 @@ class Utils {
440
415
  let hasTopLevelServers = false;
441
416
  let hasPathLevelServers = false;
442
417
  let hasOperationLevelServers = false;
443
- const allowHttp = options.projectType === exports.ProjectType.Copilot;
444
418
  if (spec.servers && spec.servers.length >= 1) {
445
419
  hasTopLevelServers = true;
446
420
  // for multiple server, we only use the first url
447
- const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
421
+ const serverErrors = Utils.checkServerUrl(spec.servers);
448
422
  errors.push(...serverErrors);
449
423
  }
450
424
  const paths = spec.paths;
@@ -452,7 +426,7 @@ class Utils {
452
426
  const methods = paths[path];
453
427
  if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
454
428
  hasPathLevelServers = true;
455
- const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
429
+ const serverErrors = Utils.checkServerUrl(methods.servers);
456
430
  errors.push(...serverErrors);
457
431
  }
458
432
  for (const method in methods) {
@@ -460,7 +434,7 @@ class Utils {
460
434
  if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
461
435
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
462
436
  hasOperationLevelServers = true;
463
- const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
437
+ const serverErrors = Utils.checkServerUrl(operationObject.servers);
464
438
  errors.push(...serverErrors);
465
439
  }
466
440
  }
@@ -749,6 +723,22 @@ class Validator {
749
723
  }
750
724
  return result;
751
725
  }
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
+ }
752
742
  validateServer(method, path) {
753
743
  const result = { isValid: true, reason: [] };
754
744
  const serverObj = Utils.getServerObject(this.spec, method, path);
@@ -757,8 +747,8 @@ class Validator {
757
747
  result.reason.push(exports.ErrorType.NoServerInformation);
758
748
  }
759
749
  else {
760
- const allowHttp = this.projectType === exports.ProjectType.Copilot;
761
- const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
750
+ // server url should be absolute url with https protocol
751
+ const serverValidateResult = Utils.checkServerUrl([serverObj]);
762
752
  result.reason.push(...serverValidateResult.map((item) => item.type));
763
753
  }
764
754
  return result;
@@ -781,9 +771,6 @@ class Validator {
781
771
  reason: [exports.ErrorType.MultipleAuthNotSupported],
782
772
  };
783
773
  }
784
- if (this.projectType === exports.ProjectType.Copilot) {
785
- return { isValid: true, reason: [] };
786
- }
787
774
  for (const auths of authSchemeArray) {
788
775
  if (auths.length === 1) {
789
776
  if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
@@ -796,6 +783,114 @@ class Validator {
796
783
  }
797
784
  return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
798
785
  }
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
+ }
799
894
  }
800
895
 
801
896
  // Copyright (c) Microsoft Corporation.
@@ -805,6 +900,7 @@ class CopilotValidator extends Validator {
805
900
  this.projectType = exports.ProjectType.Copilot;
806
901
  this.options = options;
807
902
  this.spec = spec;
903
+ this.checkCircularReference();
808
904
  }
809
905
  validateSpec() {
810
906
  const result = { errors: [], warnings: [] };
@@ -830,6 +926,10 @@ class CopilotValidator extends Validator {
830
926
  if (!methodAndPathResult.isValid) {
831
927
  return methodAndPathResult;
832
928
  }
929
+ const circularReferenceResult = this.validateCircularReference(method, path);
930
+ if (!circularReferenceResult.isValid) {
931
+ return circularReferenceResult;
932
+ }
833
933
  const operationObject = this.spec.paths[path][method];
834
934
  // validate auth
835
935
  const authCheckResult = this.validateAuth(method, path);
@@ -841,6 +941,24 @@ class CopilotValidator extends Validator {
841
941
  // validate server
842
942
  const validateServerResult = this.validateServer(method, path);
843
943
  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);
844
962
  if (result.reason.length > 0) {
845
963
  result.isValid = false;
846
964
  }
@@ -932,108 +1050,6 @@ class SMEValidator extends Validator {
932
1050
  }
933
1051
  return result;
934
1052
  }
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
- }
1037
1053
  validateParamCount(postBodyResult, paramResult) {
1038
1054
  const result = { isValid: true, reason: [] };
1039
1055
  const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
@@ -1735,7 +1751,7 @@ function inferProperties(card) {
1735
1751
 
1736
1752
  // Copyright (c) Microsoft Corporation.
1737
1753
  class ManifestUpdater {
1738
- static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authMap, existingPluginManifestInfo) {
1754
+ static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authInfo, existingPluginManifestInfo) {
1739
1755
  return __awaiter(this, void 0, void 0, function* () {
1740
1756
  const manifest = yield fs__default['default'].readJSON(manifestPath);
1741
1757
  const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
@@ -1766,7 +1782,7 @@ class ManifestUpdater {
1766
1782
  }
1767
1783
  const appName = this.removeEnvs(manifest.name.short);
1768
1784
  const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
1769
- const [apiPlugin, warnings] = yield ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo);
1785
+ const [apiPlugin, warnings] = yield ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo);
1770
1786
  return [manifest, apiPlugin, warnings];
1771
1787
  });
1772
1788
  }
@@ -1789,14 +1805,29 @@ class ManifestUpdater {
1789
1805
  throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), exports.ErrorType.UpdateManifestFailed);
1790
1806
  }
1791
1807
  }
1792
- static generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo) {
1808
+ static generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo) {
1793
1809
  var _a, _b, _c, _d;
1794
1810
  return __awaiter(this, void 0, void 0, function* () {
1795
1811
  const warnings = [];
1796
1812
  const functions = [];
1797
- const functionNamesMap = {};
1813
+ const functionNames = [];
1798
1814
  const conversationStarters = [];
1799
1815
  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
+ }
1800
1831
  for (const pathUrl in paths) {
1801
1832
  const pathItem = paths[pathUrl];
1802
1833
  if (pathItem) {
@@ -1804,11 +1835,36 @@ class ManifestUpdater {
1804
1835
  for (const method in operations) {
1805
1836
  if (options.allowMethods.includes(method)) {
1806
1837
  const operationItem = operations[method];
1838
+ const confirmationBodies = [];
1807
1839
  if (operationItem) {
1808
1840
  const operationId = operationItem.operationId;
1809
1841
  const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
1810
1842
  const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1811
1843
  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
+ }
1812
1868
  let funcDescription = operationItem.description || operationItem.summary || "";
1813
1869
  if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
1814
1870
  warnings.push({
@@ -1842,66 +1898,19 @@ class ManifestUpdater {
1842
1898
  }
1843
1899
  }
1844
1900
  if (options.allowConfirmation && method !== ConstantString.GetMethod) {
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
- }
1901
+ if (!funcObj.capabilities) {
1902
+ funcObj.capabilities = {};
1869
1903
  }
1904
+ funcObj.capabilities.confirmation = {
1905
+ type: "AdaptiveCard",
1906
+ title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
1907
+ };
1870
1908
  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
- };
1878
1909
  funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
1879
1910
  }
1880
1911
  }
1881
1912
  functions.push(funcObj);
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
- }
1913
+ functionNames.push(safeFunctionName);
1905
1914
  const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
1906
1915
  if (conversationStarterStr) {
1907
1916
  conversationStarters.push(conversationStarterStr);
@@ -1911,12 +1920,6 @@ class ManifestUpdater {
1911
1920
  }
1912
1921
  }
1913
1922
  }
1914
- if (Object.keys(functionNamesMap).length === 0) {
1915
- functionNamesMap["None"] = {
1916
- functionNames: [],
1917
- authName: "None",
1918
- };
1919
- }
1920
1923
  let apiPlugin;
1921
1924
  if (yield fs__default['default'].pathExists(apiPluginFilePath)) {
1922
1925
  apiPlugin = yield fs__default['default'].readJSON(apiPluginFilePath);
@@ -1952,35 +1955,24 @@ class ManifestUpdater {
1952
1955
  const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
1953
1956
  apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
1954
1957
  }
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;
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,
1970
1972
  });
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
- }
1973
+ }
1974
+ else {
1975
+ apiPlugin.runtimes[index].run_for_functions = functionNames;
1984
1976
  }
1985
1977
  if (!apiPlugin.name_for_human) {
1986
1978
  apiPlugin.name_for_human = appName;
@@ -2023,7 +2015,7 @@ class ManifestUpdater {
2023
2015
  };
2024
2016
  if (authInfo) {
2025
2017
  const auth = authInfo.authScheme;
2026
- const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
2018
+ const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
2027
2019
  if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
2028
2020
  composeExtension.authorization = {
2029
2021
  authType: "apiSecretServiceAuth",
@@ -2153,7 +2145,6 @@ class SpecParser {
2153
2145
  };
2154
2146
  this.pathOrSpec = pathOrDoc;
2155
2147
  this.parser = new SwaggerParser__default['default']();
2156
- this.refParser = new jsonSchemaRefParser.$RefParser();
2157
2148
  this.options = Object.assign(Object.assign({}, this.defaultOptions), (options !== null && options !== void 0 ? options : {}));
2158
2149
  }
2159
2150
  /**
@@ -2167,15 +2158,12 @@ class SpecParser {
2167
2158
  let hash = "";
2168
2159
  try {
2169
2160
  yield this.loadSpec();
2170
- if (!this.refParser.$refs.circular) {
2161
+ if (!this.parser.$refs.circular) {
2171
2162
  yield this.parser.validate(this.spec);
2172
2163
  }
2173
2164
  else {
2174
- // The following code hangs for Graph API, support will be added when SwaggerParser is updated.
2175
- /*
2176
2165
  const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
2177
- await this.parser.validate(clonedUnResolveSpec);
2178
- */
2166
+ yield this.parser.validate(clonedUnResolveSpec);
2179
2167
  }
2180
2168
  }
2181
2169
  catch (e) {
@@ -2203,7 +2191,7 @@ class SpecParser {
2203
2191
  };
2204
2192
  }
2205
2193
  // Remote reference not supported
2206
- const refPaths = this.refParser.$refs.paths();
2194
+ const refPaths = this.parser.$refs.paths();
2207
2195
  // refPaths [0] is the current spec file path
2208
2196
  if (refPaths.length > 1) {
2209
2197
  errors.push({
@@ -2338,7 +2326,7 @@ class SpecParser {
2338
2326
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
2339
2327
  }
2340
2328
  const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
2341
- const newSpec = yield this.deReferenceSpec(clonedUnResolveSpec);
2329
+ const newSpec = (yield this.parser.dereference(clonedUnResolveSpec));
2342
2330
  return [newUnResolvedSpec, newSpec];
2343
2331
  }
2344
2332
  catch (err) {
@@ -2349,12 +2337,6 @@ class SpecParser {
2349
2337
  }
2350
2338
  });
2351
2339
  }
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
- }
2358
2340
  /**
2359
2341
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
2360
2342
  * @param manifestPath A file path of the Teams app manifest file to update.
@@ -2372,6 +2354,7 @@ class SpecParser {
2372
2354
  const newSpecs = yield this.getFilteredSpecs(filter, signal);
2373
2355
  const newUnResolvedSpec = newSpecs[0];
2374
2356
  const newSpec = newSpecs[1];
2357
+ const authInfo = Utils.getAuthInfo(newSpec);
2375
2358
  const paths = newUnResolvedSpec.paths;
2376
2359
  for (const pathUrl in paths) {
2377
2360
  const operations = paths[pathUrl];
@@ -2379,22 +2362,15 @@ class SpecParser {
2379
2362
  const operationItem = operations[method];
2380
2363
  const operationId = operationItem.operationId;
2381
2364
  const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
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
- });
2365
+ if (!containsSpecialCharacters) {
2366
+ continue;
2397
2367
  }
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
+ });
2398
2374
  }
2399
2375
  }
2400
2376
  yield this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
@@ -2407,8 +2383,7 @@ class SpecParser {
2407
2383
  specPath: this.pathOrSpec,
2408
2384
  }
2409
2385
  : undefined;
2410
- const authMap = Utils.getAuthMap(newSpec);
2411
- const [updatedManifest, apiPlugin, warnings] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authMap, existingPluginManifestInfo);
2386
+ const [updatedManifest, apiPlugin, warnings] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authInfo, existingPluginManifestInfo);
2412
2387
  result.warnings.push(...warnings);
2413
2388
  yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 4 });
2414
2389
  yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
@@ -2500,7 +2475,7 @@ class SpecParser {
2500
2475
  this.isSwaggerFile = true;
2501
2476
  }
2502
2477
  const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
2503
- this.spec = yield this.deReferenceSpec(clonedUnResolveSpec);
2478
+ this.spec = (yield this.parser.dereference(clonedUnResolveSpec));
2504
2479
  }
2505
2480
  });
2506
2481
  }