@microsoft/m365-spec-parser 0.1.1-alpha.8d8f5a0bb.0 → 0.1.1-alpha.a277dba4e.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,8 @@ 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
+ ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
49
50
  ErrorType["ListFailed"] = "list-failed";
50
51
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
51
52
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -76,7 +77,13 @@ var ValidationStatus;
76
77
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
77
78
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
78
79
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
79
- })(ValidationStatus || (ValidationStatus = {}));
80
+ })(ValidationStatus || (ValidationStatus = {}));
81
+ var ProjectType;
82
+ (function (ProjectType) {
83
+ ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
84
+ ProjectType[ProjectType["SME"] = 1] = "SME";
85
+ ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
86
+ })(ProjectType || (ProjectType = {}));
80
87
 
81
88
  // Copyright (c) Microsoft Corporation.
82
89
  class SpecParserError extends Error {
@@ -103,7 +110,8 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
103
110
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
104
111
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
105
112
  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.";
113
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
114
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
107
115
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
108
116
  ConstantString.WrappedCardVersion = "devPreview";
109
117
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
@@ -116,6 +124,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
116
124
  ConstantString.TextBlockType = "TextBlock";
117
125
  ConstantString.ContainerType = "Container";
118
126
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
127
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
119
128
  ConstantString.ResponseCodeFor20X = [
120
129
  "200",
121
130
  "201",
@@ -175,7 +184,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
175
184
  ConstantString.CommandDescriptionMaxLens = 128;
176
185
  ConstantString.ParameterDescriptionMaxLens = 128;
177
186
  ConstantString.CommandTitleMaxLens = 32;
178
- ConstantString.ParameterTitleMaxLens = 32;
187
+ ConstantString.ParameterTitleMaxLens = 32;
188
+ ConstantString.SMERequiredParamsMaxNum = 5;
179
189
 
180
190
  // Copyright (c) Microsoft Corporation.
181
191
  class Utils {
@@ -288,6 +298,9 @@ class Utils {
288
298
  }
289
299
  return paramResult;
290
300
  }
301
+ static containMultipleMediaTypes(bodyObject) {
302
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
303
+ }
291
304
  /**
292
305
  * Checks if the given API is supported.
293
306
  * @param {string} method - The HTTP method of the API.
@@ -302,32 +315,40 @@ class Utils {
302
315
  * 5. response body should be “application/json” and not empty, and response code should be 20X
303
316
  * 6. only support request body with “application/json” content type
304
317
  */
305
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
318
+ static isSupportedApi(method, path, spec, options) {
319
+ var _a;
306
320
  const pathObj = spec.paths[path];
307
321
  method = method.toLocaleLowerCase();
308
322
  if (pathObj) {
309
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
310
- pathObj[method]) {
323
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
311
324
  const securities = pathObj[method].security;
312
- const authArray = Utils.getAuthArray(securities, spec);
313
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
314
- return false;
325
+ const isTeamsAi = options.projectType === ProjectType.TeamsAi;
326
+ const isCopilot = options.projectType === ProjectType.Copilot;
327
+ // Teams AI project doesn't care about auth, it will use authProvider for user to implement
328
+ if (!isTeamsAi) {
329
+ const authArray = Utils.getAuthArray(securities, spec);
330
+ if (!Utils.isSupportedAuth(authArray, options)) {
331
+ return false;
332
+ }
315
333
  }
316
334
  const operationObject = pathObj[method];
317
- if (!allowMissingId && !operationObject.operationId) {
335
+ if (!options.allowMissingId && !operationObject.operationId) {
318
336
  return false;
319
337
  }
320
338
  const paramObject = operationObject.parameters;
321
339
  const requestBody = operationObject.requestBody;
322
340
  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) {
341
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
325
342
  return false;
326
343
  }
327
- const responseJson = Utils.getResponseJson(operationObject);
344
+ const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
328
345
  if (Object.keys(responseJson).length === 0) {
329
346
  return false;
330
347
  }
348
+ // Teams AI project doesn't care about request parameters/body
349
+ if (isTeamsAi) {
350
+ return true;
351
+ }
331
352
  let requestBodyParamResult = {
332
353
  requiredNum: 0,
333
354
  optionalNum: 0,
@@ -352,8 +373,9 @@ class Utils {
352
373
  return true;
353
374
  }
354
375
  if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
355
- if (allowMultipleParameters &&
356
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
376
+ if (options.allowMultipleParameters &&
377
+ requestBodyParamResult.requiredNum + paramResult.requiredNum <=
378
+ ConstantString.SMERequiredParamsMaxNum) {
357
379
  return true;
358
380
  }
359
381
  return false;
@@ -372,29 +394,20 @@ class Utils {
372
394
  }
373
395
  return false;
374
396
  }
375
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
376
- if (authSchemaArray.length === 0) {
397
+ static isSupportedAuth(authSchemeArray, options) {
398
+ if (authSchemeArray.length === 0) {
377
399
  return true;
378
400
  }
379
- if (allowAPIKeyAuth || allowOauth2) {
401
+ if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
380
402
  // Currently we don't support multiple auth in one operation
381
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
403
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
382
404
  return false;
383
405
  }
384
- for (const auths of authSchemaArray) {
406
+ for (const auths of authSchemeArray) {
385
407
  if (auths.length === 1) {
386
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
387
- return true;
388
- }
389
- else if (!allowAPIKeyAuth &&
390
- allowOauth2 &&
391
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
392
- return true;
393
- }
394
- else if (allowAPIKeyAuth &&
395
- allowOauth2 &&
396
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
397
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
408
+ if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
409
+ (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
410
+ (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
398
411
  return true;
399
412
  }
400
413
  }
@@ -402,13 +415,17 @@ class Utils {
402
415
  }
403
416
  return false;
404
417
  }
405
- static isAPIKeyAuth(authSchema) {
406
- return authSchema.type === "apiKey";
418
+ static isBearerTokenAuth(authScheme) {
419
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
407
420
  }
408
- static isBearerTokenAuth(authSchema) {
409
- return (authSchema.type === "oauth2" ||
410
- authSchema.type === "openIdConnect" ||
411
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
421
+ static isAPIKeyAuth(authScheme) {
422
+ return authScheme.type === "apiKey";
423
+ }
424
+ static isOAuthWithAuthCodeFlow(authScheme) {
425
+ if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
426
+ return true;
427
+ }
428
+ return false;
412
429
  }
413
430
  static getAuthArray(securities, spec) {
414
431
  var _a;
@@ -421,7 +438,7 @@ class Utils {
421
438
  for (const name in security) {
422
439
  const auth = securitySchemas[name];
423
440
  authArray.push({
424
- authSchema: auth,
441
+ authScheme: auth,
425
442
  name: name,
426
443
  });
427
444
  }
@@ -436,18 +453,19 @@ class Utils {
436
453
  static updateFirstLetter(str) {
437
454
  return str.charAt(0).toUpperCase() + str.slice(1);
438
455
  }
439
- static getResponseJson(operationObject) {
456
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
440
457
  var _a, _b;
441
458
  let json = {};
442
459
  for (const code of ConstantString.ResponseCodeFor20X) {
443
460
  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
461
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
449
462
  json = responseObject.content["application/json"];
450
- break;
463
+ if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
464
+ json = {};
465
+ }
466
+ else {
467
+ break;
468
+ }
451
469
  }
452
470
  }
453
471
  return json;
@@ -521,7 +539,7 @@ class Utils {
521
539
  }
522
540
  return errors;
523
541
  }
524
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
542
+ static validateServer(spec, options) {
525
543
  const errors = [];
526
544
  let hasTopLevelServers = false;
527
545
  let hasPathLevelServers = false;
@@ -542,7 +560,7 @@ class Utils {
542
560
  }
543
561
  for (const method in methods) {
544
562
  const operationObject = methods[method];
545
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot)) {
563
+ if (Utils.isSupportedApi(method, path, spec, options)) {
546
564
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
547
565
  hasOperationLevelServers = true;
548
566
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -585,6 +603,7 @@ class Utils {
585
603
  Utils.updateParameterWithInputType(schema, parameter);
586
604
  }
587
605
  if (isRequired && schema.default === undefined) {
606
+ parameter.isRequired = true;
588
607
  requiredParams.push(parameter);
589
608
  }
590
609
  else {
@@ -629,7 +648,7 @@ class Utils {
629
648
  param.value = schema.default;
630
649
  }
631
650
  }
632
- static parseApiInfo(operationItem, allowMultipleParameters) {
651
+ static parseApiInfo(operationItem, options) {
633
652
  var _a, _b;
634
653
  const requiredParams = [];
635
654
  const optionalParams = [];
@@ -643,11 +662,12 @@ class Utils {
643
662
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
644
663
  };
645
664
  const schema = param.schema;
646
- if (allowMultipleParameters && schema) {
665
+ if (options.allowMultipleParameters && schema) {
647
666
  Utils.updateParameterWithInputType(schema, parameter);
648
667
  }
649
668
  if (param.in !== "header" && param.in !== "cookie") {
650
669
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
670
+ parameter.isRequired = true;
651
671
  requiredParams.push(parameter);
652
672
  }
653
673
  else {
@@ -661,7 +681,7 @@ class Utils {
661
681
  const requestJson = requestBody.content["application/json"];
662
682
  if (Object.keys(requestJson).length !== 0) {
663
683
  const schema = requestJson.schema;
664
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
684
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
665
685
  requiredParams.push(...requiredP);
666
686
  optionalParams.push(...optionalP);
667
687
  }
@@ -692,14 +712,13 @@ class Utils {
692
712
  }
693
713
  return [command, warning];
694
714
  }
695
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
715
+ static listSupportedAPIs(spec, options) {
696
716
  const paths = spec.paths;
697
717
  const result = {};
698
718
  for (const path in paths) {
699
719
  const methods = paths[path];
700
720
  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)) {
721
+ if (Utils.isSupportedApi(method, path, spec, options)) {
703
722
  const operationObject = methods[method];
704
723
  result[`${method.toUpperCase()} ${path}`] = operationObject;
705
724
  }
@@ -707,7 +726,7 @@ class Utils {
707
726
  }
708
727
  return result;
709
728
  }
710
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot) {
729
+ static validateSpec(spec, parser, isSwaggerFile, options) {
711
730
  const errors = [];
712
731
  const warnings = [];
713
732
  if (isSwaggerFile) {
@@ -717,7 +736,7 @@ class Utils {
717
736
  });
718
737
  }
719
738
  // Server validation
720
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot);
739
+ const serverErrors = Utils.validateServer(spec, options);
721
740
  errors.push(...serverErrors);
722
741
  // Remote reference not supported
723
742
  const refPaths = parser.$refs.paths();
@@ -730,7 +749,7 @@ class Utils {
730
749
  });
731
750
  }
732
751
  // No supported API
733
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot);
752
+ const apiMap = Utils.listSupportedAPIs(spec, options);
734
753
  if (Object.keys(apiMap).length === 0) {
735
754
  errors.push({
736
755
  type: ErrorType.NoSupportedApi,
@@ -782,6 +801,19 @@ class Utils {
782
801
  }
783
802
  return safeRegistrationIdEnvName;
784
803
  }
804
+ static getAllAPICount(spec) {
805
+ let count = 0;
806
+ const paths = spec.paths;
807
+ for (const path in paths) {
808
+ const methods = paths[path];
809
+ for (const method in methods) {
810
+ if (ConstantString.AllOperationMethods.includes(method)) {
811
+ count++;
812
+ }
813
+ }
814
+ }
815
+ return count;
816
+ }
785
817
  }
786
818
 
787
819
  // Copyright (c) Microsoft Corporation.
@@ -800,8 +832,10 @@ class SpecParser {
800
832
  allowSwagger: false,
801
833
  allowAPIKeyAuth: false,
802
834
  allowMultipleParameters: false,
835
+ allowBearerTokenAuth: false,
803
836
  allowOauth2: false,
804
- isCopilot: false,
837
+ allowMethods: ["get", "post"],
838
+ projectType: ProjectType.SME,
805
839
  };
806
840
  this.pathOrSpec = pathOrDoc;
807
841
  this.parser = new SwaggerParser();
@@ -839,7 +873,7 @@ class SpecParser {
839
873
  ],
840
874
  };
841
875
  }
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);
876
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
843
877
  }
844
878
  catch (err) {
845
879
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -860,7 +894,7 @@ class SpecParser {
860
894
  if (!operationId) {
861
895
  continue;
862
896
  }
863
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options.allowMultipleParameters);
897
+ const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
864
898
  const apiInfo = {
865
899
  method: method,
866
900
  path: path,
@@ -924,7 +958,7 @@ class SpecParser {
924
958
  * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
925
959
  */
926
960
  // eslint-disable-next-line @typescript-eslint/require-await
927
- generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal, isMe) {
961
+ generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
928
962
  return __awaiter(this, void 0, void 0, function* () {
929
963
  throw new Error("Method not implemented.");
930
964
  });
@@ -945,7 +979,7 @@ class SpecParser {
945
979
  if (this.apiMap !== undefined) {
946
980
  return this.apiMap;
947
981
  }
948
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2, this.options.isCopilot);
982
+ const result = Utils.listSupportedAPIs(spec, this.options);
949
983
  this.apiMap = result;
950
984
  return result;
951
985
  }