@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.
@@ -45,7 +45,7 @@ var ErrorType;
45
45
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
46
46
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
47
47
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
48
- ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
48
+ ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
49
49
  ErrorType["ListFailed"] = "list-failed";
50
50
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
51
51
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -76,7 +76,13 @@ var ValidationStatus;
76
76
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
77
77
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
78
78
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
79
- })(ValidationStatus || (ValidationStatus = {}));
79
+ })(ValidationStatus || (ValidationStatus = {}));
80
+ var ProjectType;
81
+ (function (ProjectType) {
82
+ ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
83
+ ProjectType[ProjectType["SME"] = 1] = "SME";
84
+ ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
85
+ })(ProjectType || (ProjectType = {}));
80
86
 
81
87
  // Copyright (c) Microsoft Corporation.
82
88
  class SpecParserError extends Error {
@@ -103,7 +109,7 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
103
109
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
104
110
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
105
111
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
106
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
112
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
107
113
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
108
114
  ConstantString.WrappedCardVersion = "devPreview";
109
115
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
@@ -116,6 +122,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
116
122
  ConstantString.TextBlockType = "TextBlock";
117
123
  ConstantString.ContainerType = "Container";
118
124
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
125
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
119
126
  ConstantString.ResponseCodeFor20X = [
120
127
  "200",
121
128
  "201",
@@ -175,7 +182,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
175
182
  ConstantString.CommandDescriptionMaxLens = 128;
176
183
  ConstantString.ParameterDescriptionMaxLens = 128;
177
184
  ConstantString.CommandTitleMaxLens = 32;
178
- ConstantString.ParameterTitleMaxLens = 32;
185
+ ConstantString.ParameterTitleMaxLens = 32;
186
+ ConstantString.SMERequiredParamsMaxNum = 5;
179
187
 
180
188
  // Copyright (c) Microsoft Corporation.
181
189
  class Utils {
@@ -288,6 +296,9 @@ class Utils {
288
296
  }
289
297
  return paramResult;
290
298
  }
299
+ static containMultipleMediaTypes(bodyObject) {
300
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
301
+ }
291
302
  /**
292
303
  * Checks if the given API is supported.
293
304
  * @param {string} method - The HTTP method of the API.
@@ -302,32 +313,40 @@ class Utils {
302
313
  * 5. response body should be “application/json” and not empty, and response code should be 20X
303
314
  * 6. only support request body with “application/json” content type
304
315
  */
305
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
316
+ static isSupportedApi(method, path, spec, options) {
317
+ var _a;
306
318
  const pathObj = spec.paths[path];
307
319
  method = method.toLocaleLowerCase();
308
320
  if (pathObj) {
309
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
310
- pathObj[method]) {
321
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
311
322
  const securities = pathObj[method].security;
312
- const authArray = Utils.getAuthArray(securities, spec);
313
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
314
- return false;
323
+ const isTeamsAi = options.projectType === ProjectType.TeamsAi;
324
+ const isCopilot = options.projectType === ProjectType.Copilot;
325
+ // Teams AI project doesn't care about auth, it will use authProvider for user to implement
326
+ if (!isTeamsAi) {
327
+ const authArray = Utils.getAuthArray(securities, spec);
328
+ if (!Utils.isSupportedAuth(authArray, options)) {
329
+ return false;
330
+ }
315
331
  }
316
332
  const operationObject = pathObj[method];
317
- if (!allowMissingId && !operationObject.operationId) {
333
+ if (!options.allowMissingId && !operationObject.operationId) {
318
334
  return false;
319
335
  }
320
336
  const paramObject = operationObject.parameters;
321
337
  const requestBody = operationObject.requestBody;
322
338
  const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
323
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
324
- if (mediaTypesCount > 1) {
339
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
325
340
  return false;
326
341
  }
327
- const responseJson = Utils.getResponseJson(operationObject);
342
+ const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
328
343
  if (Object.keys(responseJson).length === 0) {
329
344
  return false;
330
345
  }
346
+ // Teams AI project doesn't care about request parameters/body
347
+ if (isTeamsAi) {
348
+ return true;
349
+ }
331
350
  let requestBodyParamResult = {
332
351
  requiredNum: 0,
333
352
  optionalNum: 0,
@@ -352,8 +371,9 @@ class Utils {
352
371
  return true;
353
372
  }
354
373
  if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
355
- if (allowMultipleParameters &&
356
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
374
+ if (options.allowMultipleParameters &&
375
+ requestBodyParamResult.requiredNum + paramResult.requiredNum <=
376
+ ConstantString.SMERequiredParamsMaxNum) {
357
377
  return true;
358
378
  }
359
379
  return false;
@@ -372,29 +392,31 @@ class Utils {
372
392
  }
373
393
  return false;
374
394
  }
375
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
395
+ static isSupportedAuth(authSchemaArray, options) {
376
396
  if (authSchemaArray.length === 0) {
377
397
  return true;
378
398
  }
379
- if (allowAPIKeyAuth || allowOauth2) {
399
+ if (options.allowAPIKeyAuth || options.allowOauth2) {
380
400
  // Currently we don't support multiple auth in one operation
381
401
  if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
382
402
  return false;
383
403
  }
384
404
  for (const auths of authSchemaArray) {
385
405
  if (auths.length === 1) {
386
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
406
+ if (!options.allowOauth2 &&
407
+ options.allowAPIKeyAuth &&
408
+ Utils.isAPIKeyAuth(auths[0].authSchema)) {
387
409
  return true;
388
410
  }
389
- else if (!allowAPIKeyAuth &&
390
- allowOauth2 &&
391
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
411
+ else if (!options.allowAPIKeyAuth &&
412
+ options.allowOauth2 &&
413
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema)) {
392
414
  return true;
393
415
  }
394
- else if (allowAPIKeyAuth &&
395
- allowOauth2 &&
416
+ else if (options.allowAPIKeyAuth &&
417
+ options.allowOauth2 &&
396
418
  (Utils.isAPIKeyAuth(auths[0].authSchema) ||
397
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
419
+ Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema))) {
398
420
  return true;
399
421
  }
400
422
  }
@@ -405,10 +427,11 @@ class Utils {
405
427
  static isAPIKeyAuth(authSchema) {
406
428
  return authSchema.type === "apiKey";
407
429
  }
408
- static isBearerTokenAuth(authSchema) {
409
- return (authSchema.type === "oauth2" ||
410
- authSchema.type === "openIdConnect" ||
411
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
430
+ static isOAuthWithAuthCodeFlow(authSchema) {
431
+ if (authSchema.type === "oauth2" && authSchema.flows && authSchema.flows.authorizationCode) {
432
+ return true;
433
+ }
434
+ return false;
412
435
  }
413
436
  static getAuthArray(securities, spec) {
414
437
  var _a;
@@ -436,18 +459,19 @@ class Utils {
436
459
  static updateFirstLetter(str) {
437
460
  return str.charAt(0).toUpperCase() + str.slice(1);
438
461
  }
439
- static getResponseJson(operationObject) {
462
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
440
463
  var _a, _b;
441
464
  let json = {};
442
465
  for (const code of ConstantString.ResponseCodeFor20X) {
443
466
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
444
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
445
- if (mediaTypesCount > 1) {
446
- return {};
447
- }
448
467
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
449
468
  json = responseObject.content["application/json"];
450
- break;
469
+ if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
470
+ json = {};
471
+ }
472
+ else {
473
+ break;
474
+ }
451
475
  }
452
476
  }
453
477
  return json;
@@ -521,7 +545,7 @@ class Utils {
521
545
  }
522
546
  return errors;
523
547
  }
524
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
548
+ static validateServer(spec, options) {
525
549
  const errors = [];
526
550
  let hasTopLevelServers = false;
527
551
  let hasPathLevelServers = false;
@@ -542,7 +566,7 @@ class Utils {
542
566
  }
543
567
  for (const method in methods) {
544
568
  const operationObject = methods[method];
545
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot)) {
569
+ if (Utils.isSupportedApi(method, path, spec, options)) {
546
570
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
547
571
  hasOperationLevelServers = true;
548
572
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -629,7 +653,7 @@ class Utils {
629
653
  param.value = schema.default;
630
654
  }
631
655
  }
632
- static parseApiInfo(operationItem, allowMultipleParameters) {
656
+ static parseApiInfo(operationItem, options) {
633
657
  var _a, _b;
634
658
  const requiredParams = [];
635
659
  const optionalParams = [];
@@ -643,7 +667,7 @@ class Utils {
643
667
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
644
668
  };
645
669
  const schema = param.schema;
646
- if (allowMultipleParameters && schema) {
670
+ if (options.allowMultipleParameters && schema) {
647
671
  Utils.updateParameterWithInputType(schema, parameter);
648
672
  }
649
673
  if (param.in !== "header" && param.in !== "cookie") {
@@ -661,7 +685,7 @@ class Utils {
661
685
  const requestJson = requestBody.content["application/json"];
662
686
  if (Object.keys(requestJson).length !== 0) {
663
687
  const schema = requestJson.schema;
664
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
688
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
665
689
  requiredParams.push(...requiredP);
666
690
  optionalParams.push(...optionalP);
667
691
  }
@@ -692,14 +716,13 @@ class Utils {
692
716
  }
693
717
  return [command, warning];
694
718
  }
695
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
719
+ static listSupportedAPIs(spec, options) {
696
720
  const paths = spec.paths;
697
721
  const result = {};
698
722
  for (const path in paths) {
699
723
  const methods = paths[path];
700
724
  for (const method in methods) {
701
- // For developer preview, only support GET operation with only 1 parameter without auth
702
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot)) {
725
+ if (Utils.isSupportedApi(method, path, spec, options)) {
703
726
  const operationObject = methods[method];
704
727
  result[`${method.toUpperCase()} ${path}`] = operationObject;
705
728
  }
@@ -707,7 +730,7 @@ class Utils {
707
730
  }
708
731
  return result;
709
732
  }
710
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
733
+ static validateSpec(spec, parser, isSwaggerFile, options) {
711
734
  const errors = [];
712
735
  const warnings = [];
713
736
  if (isSwaggerFile) {
@@ -717,7 +740,7 @@ class Utils {
717
740
  });
718
741
  }
719
742
  // Server validation
720
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot);
743
+ const serverErrors = Utils.validateServer(spec, options);
721
744
  errors.push(...serverErrors);
722
745
  // Remote reference not supported
723
746
  const refPaths = parser.$refs.paths();
@@ -730,7 +753,7 @@ class Utils {
730
753
  });
731
754
  }
732
755
  // No supported API
733
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot);
756
+ const apiMap = Utils.listSupportedAPIs(spec, options);
734
757
  if (Object.keys(apiMap).length === 0) {
735
758
  errors.push({
736
759
  type: ErrorType.NoSupportedApi,
@@ -801,7 +824,8 @@ class SpecParser {
801
824
  allowAPIKeyAuth: false,
802
825
  allowMultipleParameters: false,
803
826
  allowOauth2: false,
804
- isCopilot: false,
827
+ allowMethods: ["get", "post"],
828
+ projectType: ProjectType.SME,
805
829
  };
806
830
  this.pathOrSpec = pathOrDoc;
807
831
  this.parser = new SwaggerParser();
@@ -839,7 +863,7 @@ class SpecParser {
839
863
  ],
840
864
  };
841
865
  }
842
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2, this.options.isCopilot);
866
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
843
867
  }
844
868
  catch (err) {
845
869
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -860,7 +884,7 @@ class SpecParser {
860
884
  if (!operationId) {
861
885
  continue;
862
886
  }
863
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options.allowMultipleParameters);
887
+ const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
864
888
  const apiInfo = {
865
889
  method: method,
866
890
  path: path,
@@ -924,7 +948,7 @@ class SpecParser {
924
948
  * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
925
949
  */
926
950
  // eslint-disable-next-line @typescript-eslint/require-await
927
- generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal, isMe) {
951
+ generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
928
952
  return __awaiter(this, void 0, void 0, function* () {
929
953
  throw new Error("Method not implemented.");
930
954
  });
@@ -945,7 +969,7 @@ class SpecParser {
945
969
  if (this.apiMap !== undefined) {
946
970
  return this.apiMap;
947
971
  }
948
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2, this.options.isCopilot);
972
+ const result = Utils.listSupportedAPIs(spec, this.options);
949
973
  this.apiMap = result;
950
974
  return result;
951
975
  }