@microsoft/m365-spec-parser 0.1.1-alpha.8d8f5a0bb.0 → 0.1.1-alpha.a372ccf67.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.
@@ -15,7 +15,7 @@ var ErrorType;
15
15
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
16
16
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
17
17
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
18
- ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
18
+ ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
19
19
  ErrorType["ListFailed"] = "list-failed";
20
20
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
21
21
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -46,7 +46,13 @@ var ValidationStatus;
46
46
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
47
47
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
48
48
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
49
- })(ValidationStatus || (ValidationStatus = {}));
49
+ })(ValidationStatus || (ValidationStatus = {}));
50
+ var ProjectType;
51
+ (function (ProjectType) {
52
+ ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
53
+ ProjectType[ProjectType["SME"] = 1] = "SME";
54
+ ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
55
+ })(ProjectType || (ProjectType = {}));
50
56
 
51
57
  // Copyright (c) Microsoft Corporation.
52
58
  class SpecParserError extends Error {
@@ -73,7 +79,7 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
73
79
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
74
80
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
75
81
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
76
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
82
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
77
83
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
78
84
  ConstantString.WrappedCardVersion = "devPreview";
79
85
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
@@ -86,6 +92,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
86
92
  ConstantString.TextBlockType = "TextBlock";
87
93
  ConstantString.ContainerType = "Container";
88
94
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
95
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
89
96
  ConstantString.ResponseCodeFor20X = [
90
97
  "200",
91
98
  "201",
@@ -145,7 +152,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
145
152
  ConstantString.CommandDescriptionMaxLens = 128;
146
153
  ConstantString.ParameterDescriptionMaxLens = 128;
147
154
  ConstantString.CommandTitleMaxLens = 32;
148
- ConstantString.ParameterTitleMaxLens = 32;
155
+ ConstantString.ParameterTitleMaxLens = 32;
156
+ ConstantString.SMERequiredParamsMaxNum = 5;
149
157
 
150
158
  // Copyright (c) Microsoft Corporation.
151
159
  class Utils {
@@ -258,6 +266,9 @@ class Utils {
258
266
  }
259
267
  return paramResult;
260
268
  }
269
+ static containMultipleMediaTypes(bodyObject) {
270
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
271
+ }
261
272
  /**
262
273
  * Checks if the given API is supported.
263
274
  * @param {string} method - The HTTP method of the API.
@@ -272,32 +283,40 @@ class Utils {
272
283
  * 5. response body should be “application/json” and not empty, and response code should be 20X
273
284
  * 6. only support request body with “application/json” content type
274
285
  */
275
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
286
+ static isSupportedApi(method, path, spec, options) {
287
+ var _a;
276
288
  const pathObj = spec.paths[path];
277
289
  method = method.toLocaleLowerCase();
278
290
  if (pathObj) {
279
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
280
- pathObj[method]) {
291
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
281
292
  const securities = pathObj[method].security;
282
- const authArray = Utils.getAuthArray(securities, spec);
283
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
284
- return false;
293
+ const isTeamsAi = options.projectType === ProjectType.TeamsAi;
294
+ const isCopilot = options.projectType === ProjectType.Copilot;
295
+ // Teams AI project doesn't care about auth, it will use authProvider for user to implement
296
+ if (!isTeamsAi) {
297
+ const authArray = Utils.getAuthArray(securities, spec);
298
+ if (!Utils.isSupportedAuth(authArray, options)) {
299
+ return false;
300
+ }
285
301
  }
286
302
  const operationObject = pathObj[method];
287
- if (!allowMissingId && !operationObject.operationId) {
303
+ if (!options.allowMissingId && !operationObject.operationId) {
288
304
  return false;
289
305
  }
290
306
  const paramObject = operationObject.parameters;
291
307
  const requestBody = operationObject.requestBody;
292
308
  const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
293
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
294
- if (mediaTypesCount > 1) {
309
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
295
310
  return false;
296
311
  }
297
- const responseJson = Utils.getResponseJson(operationObject);
312
+ const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
298
313
  if (Object.keys(responseJson).length === 0) {
299
314
  return false;
300
315
  }
316
+ // Teams AI project doesn't care about request parameters/body
317
+ if (isTeamsAi) {
318
+ return true;
319
+ }
301
320
  let requestBodyParamResult = {
302
321
  requiredNum: 0,
303
322
  optionalNum: 0,
@@ -322,8 +341,9 @@ class Utils {
322
341
  return true;
323
342
  }
324
343
  if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
325
- if (allowMultipleParameters &&
326
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
344
+ if (options.allowMultipleParameters &&
345
+ requestBodyParamResult.requiredNum + paramResult.requiredNum <=
346
+ ConstantString.SMERequiredParamsMaxNum) {
327
347
  return true;
328
348
  }
329
349
  return false;
@@ -342,29 +362,31 @@ class Utils {
342
362
  }
343
363
  return false;
344
364
  }
345
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
365
+ static isSupportedAuth(authSchemaArray, options) {
346
366
  if (authSchemaArray.length === 0) {
347
367
  return true;
348
368
  }
349
- if (allowAPIKeyAuth || allowOauth2) {
369
+ if (options.allowAPIKeyAuth || options.allowOauth2) {
350
370
  // Currently we don't support multiple auth in one operation
351
371
  if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
352
372
  return false;
353
373
  }
354
374
  for (const auths of authSchemaArray) {
355
375
  if (auths.length === 1) {
356
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
376
+ if (!options.allowOauth2 &&
377
+ options.allowAPIKeyAuth &&
378
+ Utils.isAPIKeyAuth(auths[0].authSchema)) {
357
379
  return true;
358
380
  }
359
- else if (!allowAPIKeyAuth &&
360
- allowOauth2 &&
361
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
381
+ else if (!options.allowAPIKeyAuth &&
382
+ options.allowOauth2 &&
383
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema)) {
362
384
  return true;
363
385
  }
364
- else if (allowAPIKeyAuth &&
365
- allowOauth2 &&
386
+ else if (options.allowAPIKeyAuth &&
387
+ options.allowOauth2 &&
366
388
  (Utils.isAPIKeyAuth(auths[0].authSchema) ||
367
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
389
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema))) {
368
390
  return true;
369
391
  }
370
392
  }
@@ -375,10 +397,11 @@ class Utils {
375
397
  static isAPIKeyAuth(authSchema) {
376
398
  return authSchema.type === "apiKey";
377
399
  }
378
- static isBearerTokenAuth(authSchema) {
379
- return (authSchema.type === "oauth2" ||
380
- authSchema.type === "openIdConnect" ||
381
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
400
+ static isOAuthWithAuthCodeFlow(authSchema) {
401
+ if (authSchema.type === "oauth2" && authSchema.flows && authSchema.flows.authorizationCode) {
402
+ return true;
403
+ }
404
+ return false;
382
405
  }
383
406
  static getAuthArray(securities, spec) {
384
407
  var _a;
@@ -406,18 +429,19 @@ class Utils {
406
429
  static updateFirstLetter(str) {
407
430
  return str.charAt(0).toUpperCase() + str.slice(1);
408
431
  }
409
- static getResponseJson(operationObject) {
432
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
410
433
  var _a, _b;
411
434
  let json = {};
412
435
  for (const code of ConstantString.ResponseCodeFor20X) {
413
436
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
414
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
415
- if (mediaTypesCount > 1) {
416
- return {};
417
- }
418
437
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
419
438
  json = responseObject.content["application/json"];
420
- break;
439
+ if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
440
+ json = {};
441
+ }
442
+ else {
443
+ break;
444
+ }
421
445
  }
422
446
  }
423
447
  return json;
@@ -491,7 +515,7 @@ class Utils {
491
515
  }
492
516
  return errors;
493
517
  }
494
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
518
+ static validateServer(spec, options) {
495
519
  const errors = [];
496
520
  let hasTopLevelServers = false;
497
521
  let hasPathLevelServers = false;
@@ -512,7 +536,7 @@ class Utils {
512
536
  }
513
537
  for (const method in methods) {
514
538
  const operationObject = methods[method];
515
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot)) {
539
+ if (Utils.isSupportedApi(method, path, spec, options)) {
516
540
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
517
541
  hasOperationLevelServers = true;
518
542
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -599,7 +623,7 @@ class Utils {
599
623
  param.value = schema.default;
600
624
  }
601
625
  }
602
- static parseApiInfo(operationItem, allowMultipleParameters) {
626
+ static parseApiInfo(operationItem, options) {
603
627
  var _a, _b;
604
628
  const requiredParams = [];
605
629
  const optionalParams = [];
@@ -613,7 +637,7 @@ class Utils {
613
637
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
614
638
  };
615
639
  const schema = param.schema;
616
- if (allowMultipleParameters && schema) {
640
+ if (options.allowMultipleParameters && schema) {
617
641
  Utils.updateParameterWithInputType(schema, parameter);
618
642
  }
619
643
  if (param.in !== "header" && param.in !== "cookie") {
@@ -631,7 +655,7 @@ class Utils {
631
655
  const requestJson = requestBody.content["application/json"];
632
656
  if (Object.keys(requestJson).length !== 0) {
633
657
  const schema = requestJson.schema;
634
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
658
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
635
659
  requiredParams.push(...requiredP);
636
660
  optionalParams.push(...optionalP);
637
661
  }
@@ -662,14 +686,13 @@ class Utils {
662
686
  }
663
687
  return [command, warning];
664
688
  }
665
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
689
+ static listSupportedAPIs(spec, options) {
666
690
  const paths = spec.paths;
667
691
  const result = {};
668
692
  for (const path in paths) {
669
693
  const methods = paths[path];
670
694
  for (const method in methods) {
671
- // For developer preview, only support GET operation with only 1 parameter without auth
672
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot)) {
695
+ if (Utils.isSupportedApi(method, path, spec, options)) {
673
696
  const operationObject = methods[method];
674
697
  result[`${method.toUpperCase()} ${path}`] = operationObject;
675
698
  }
@@ -677,7 +700,7 @@ class Utils {
677
700
  }
678
701
  return result;
679
702
  }
680
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
703
+ static validateSpec(spec, parser, isSwaggerFile, options) {
681
704
  const errors = [];
682
705
  const warnings = [];
683
706
  if (isSwaggerFile) {
@@ -687,7 +710,7 @@ class Utils {
687
710
  });
688
711
  }
689
712
  // Server validation
690
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot);
713
+ const serverErrors = Utils.validateServer(spec, options);
691
714
  errors.push(...serverErrors);
692
715
  // Remote reference not supported
693
716
  const refPaths = parser.$refs.paths();
@@ -700,7 +723,7 @@ class Utils {
700
723
  });
701
724
  }
702
725
  // No supported API
703
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot);
726
+ const apiMap = Utils.listSupportedAPIs(spec, options);
704
727
  if (Object.keys(apiMap).length === 0) {
705
728
  errors.push({
706
729
  type: ErrorType.NoSupportedApi,
@@ -771,7 +794,8 @@ class SpecParser {
771
794
  allowAPIKeyAuth: false,
772
795
  allowMultipleParameters: false,
773
796
  allowOauth2: false,
774
- isCopilot: false,
797
+ allowMethods: ["get", "post"],
798
+ projectType: ProjectType.SME,
775
799
  };
776
800
  this.pathOrSpec = pathOrDoc;
777
801
  this.parser = new SwaggerParser();
@@ -808,7 +832,7 @@ class SpecParser {
808
832
  ],
809
833
  };
810
834
  }
811
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2, this.options.isCopilot);
835
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
812
836
  }
813
837
  catch (err) {
814
838
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -827,7 +851,7 @@ class SpecParser {
827
851
  if (!operationId) {
828
852
  continue;
829
853
  }
830
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options.allowMultipleParameters);
854
+ const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
831
855
  const apiInfo = {
832
856
  method: method,
833
857
  path: path,
@@ -884,7 +908,7 @@ class SpecParser {
884
908
  * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
885
909
  */
886
910
  // eslint-disable-next-line @typescript-eslint/require-await
887
- async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal, isMe) {
911
+ async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
888
912
  throw new Error("Method not implemented.");
889
913
  }
890
914
  async loadSpec() {
@@ -901,7 +925,7 @@ class SpecParser {
901
925
  if (this.apiMap !== undefined) {
902
926
  return this.apiMap;
903
927
  }
904
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2, this.options.isCopilot);
928
+ const result = Utils.listSupportedAPIs(spec, this.options);
905
929
  this.apiMap = result;
906
930
  return result;
907
931
  }