@microsoft/m365-spec-parser 0.1.1-alpha.cd2ba87f2.0 → 0.1.1-alpha.d1a09e202.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";
@@ -23,6 +23,7 @@ var ErrorType;
23
23
  ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
24
24
  ErrorType["GenerateFailed"] = "generate-failed";
25
25
  ErrorType["ValidateFailed"] = "validate-failed";
26
+ ErrorType["GetSpecFailed"] = "get-spec-failed";
26
27
  ErrorType["Cancelled"] = "cancelled";
27
28
  ErrorType["Unknown"] = "unknown";
28
29
  })(ErrorType || (ErrorType = {}));
@@ -45,7 +46,13 @@ var ValidationStatus;
45
46
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
46
47
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
47
48
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
48
- })(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 = {}));
49
56
 
50
57
  // Copyright (c) Microsoft Corporation.
51
58
  class SpecParserError extends Error {
@@ -72,7 +79,8 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
72
79
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
73
80
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
74
81
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
75
- 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.";
83
+ ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
76
84
  ConstantString.WrappedCardVersion = "devPreview";
77
85
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
78
86
  ConstantString.WrappedCardResponseLayout = "list";
@@ -84,6 +92,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
84
92
  ConstantString.TextBlockType = "TextBlock";
85
93
  ConstantString.ContainerType = "Container";
86
94
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
95
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
87
96
  ConstantString.ResponseCodeFor20X = [
88
97
  "200",
89
98
  "201",
@@ -143,11 +152,23 @@ ConstantString.FullDescriptionMaxLens = 4000;
143
152
  ConstantString.CommandDescriptionMaxLens = 128;
144
153
  ConstantString.ParameterDescriptionMaxLens = 128;
145
154
  ConstantString.CommandTitleMaxLens = 32;
146
- ConstantString.ParameterTitleMaxLens = 32;
155
+ ConstantString.ParameterTitleMaxLens = 32;
156
+ ConstantString.SMERequiredParamsMaxNum = 5;
147
157
 
148
158
  // Copyright (c) Microsoft Corporation.
149
159
  class Utils {
150
- static checkParameters(paramObject) {
160
+ static hasNestedObjectInSchema(schema) {
161
+ if (schema.type === "object") {
162
+ for (const property in schema.properties) {
163
+ const nestedSchema = schema.properties[property];
164
+ if (nestedSchema.type === "object") {
165
+ return true;
166
+ }
167
+ }
168
+ }
169
+ return false;
170
+ }
171
+ static checkParameters(paramObject, isCopilot) {
151
172
  const paramResult = {
152
173
  requiredNum: 0,
153
174
  optionalNum: 0,
@@ -159,7 +180,20 @@ class Utils {
159
180
  for (let i = 0; i < paramObject.length; i++) {
160
181
  const param = paramObject[i];
161
182
  const schema = param.schema;
183
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
184
+ paramResult.isValid = false;
185
+ continue;
186
+ }
162
187
  const isRequiredWithoutDefault = param.required && schema.default === undefined;
188
+ if (isCopilot) {
189
+ if (isRequiredWithoutDefault) {
190
+ paramResult.requiredNum = paramResult.requiredNum + 1;
191
+ }
192
+ else {
193
+ paramResult.optionalNum = paramResult.optionalNum + 1;
194
+ }
195
+ continue;
196
+ }
163
197
  if (param.in === "header" || param.in === "cookie") {
164
198
  if (isRequiredWithoutDefault) {
165
199
  paramResult.isValid = false;
@@ -186,7 +220,7 @@ class Utils {
186
220
  }
187
221
  return paramResult;
188
222
  }
189
- static checkPostBody(schema, isRequired = false) {
223
+ static checkPostBody(schema, isRequired = false, isCopilot = false) {
190
224
  var _a;
191
225
  const paramResult = {
192
226
  requiredNum: 0,
@@ -197,6 +231,10 @@ class Utils {
197
231
  return paramResult;
198
232
  }
199
233
  const isRequiredWithoutDefault = isRequired && schema.default === undefined;
234
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
235
+ paramResult.isValid = false;
236
+ return paramResult;
237
+ }
200
238
  if (schema.type === "string" ||
201
239
  schema.type === "integer" ||
202
240
  schema.type === "boolean" ||
@@ -215,19 +253,22 @@ class Utils {
215
253
  if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
216
254
  isRequired = true;
217
255
  }
218
- const result = Utils.checkPostBody(properties[property], isRequired);
256
+ const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
219
257
  paramResult.requiredNum += result.requiredNum;
220
258
  paramResult.optionalNum += result.optionalNum;
221
259
  paramResult.isValid = paramResult.isValid && result.isValid;
222
260
  }
223
261
  }
224
262
  else {
225
- if (isRequiredWithoutDefault) {
263
+ if (isRequiredWithoutDefault && !isCopilot) {
226
264
  paramResult.isValid = false;
227
265
  }
228
266
  }
229
267
  return paramResult;
230
268
  }
269
+ static containMultipleMediaTypes(bodyObject) {
270
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
271
+ }
231
272
  /**
232
273
  * Checks if the given API is supported.
233
274
  * @param {string} method - The HTTP method of the API.
@@ -242,32 +283,40 @@ class Utils {
242
283
  * 5. response body should be “application/json” and not empty, and response code should be 20X
243
284
  * 6. only support request body with “application/json” content type
244
285
  */
245
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
286
+ static isSupportedApi(method, path, spec, options) {
287
+ var _a;
246
288
  const pathObj = spec.paths[path];
247
289
  method = method.toLocaleLowerCase();
248
290
  if (pathObj) {
249
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
250
- pathObj[method]) {
291
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
251
292
  const securities = pathObj[method].security;
252
- const authArray = Utils.getAuthArray(securities, spec);
253
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
254
- 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
+ }
255
301
  }
256
302
  const operationObject = pathObj[method];
257
- if (!allowMissingId && !operationObject.operationId) {
303
+ if (!options.allowMissingId && !operationObject.operationId) {
258
304
  return false;
259
305
  }
260
306
  const paramObject = operationObject.parameters;
261
307
  const requestBody = operationObject.requestBody;
262
308
  const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
263
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
264
- if (mediaTypesCount > 1) {
309
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
265
310
  return false;
266
311
  }
267
- const responseJson = Utils.getResponseJson(operationObject);
312
+ const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
268
313
  if (Object.keys(responseJson).length === 0) {
269
314
  return false;
270
315
  }
316
+ // Teams AI project doesn't care about request parameters/body
317
+ if (isTeamsAi) {
318
+ return true;
319
+ }
271
320
  let requestBodyParamResult = {
272
321
  requiredNum: 0,
273
322
  optionalNum: 0,
@@ -275,18 +324,26 @@ class Utils {
275
324
  };
276
325
  if (requestJsonBody) {
277
326
  const requestBodySchema = requestJsonBody.schema;
278
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
327
+ if (isCopilot && requestBodySchema.type !== "object") {
328
+ return false;
329
+ }
330
+ requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
279
331
  }
280
332
  if (!requestBodyParamResult.isValid) {
281
333
  return false;
282
334
  }
283
- const paramResult = Utils.checkParameters(paramObject);
335
+ const paramResult = Utils.checkParameters(paramObject, isCopilot);
284
336
  if (!paramResult.isValid) {
285
337
  return false;
286
338
  }
339
+ // Copilot support arbitrary parameters
340
+ if (isCopilot) {
341
+ return true;
342
+ }
287
343
  if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
288
- if (allowMultipleParameters &&
289
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
344
+ if (options.allowMultipleParameters &&
345
+ requestBodyParamResult.requiredNum + paramResult.requiredNum <=
346
+ ConstantString.SMERequiredParamsMaxNum) {
290
347
  return true;
291
348
  }
292
349
  return false;
@@ -305,29 +362,20 @@ class Utils {
305
362
  }
306
363
  return false;
307
364
  }
308
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
309
- if (authSchemaArray.length === 0) {
365
+ static isSupportedAuth(authSchemeArray, options) {
366
+ if (authSchemeArray.length === 0) {
310
367
  return true;
311
368
  }
312
- if (allowAPIKeyAuth || allowOauth2) {
369
+ if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
313
370
  // Currently we don't support multiple auth in one operation
314
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
371
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
315
372
  return false;
316
373
  }
317
- for (const auths of authSchemaArray) {
374
+ for (const auths of authSchemeArray) {
318
375
  if (auths.length === 1) {
319
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
320
- return true;
321
- }
322
- else if (!allowAPIKeyAuth &&
323
- allowOauth2 &&
324
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
325
- return true;
326
- }
327
- else if (allowAPIKeyAuth &&
328
- allowOauth2 &&
329
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
330
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
376
+ if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
377
+ (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
378
+ (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
331
379
  return true;
332
380
  }
333
381
  }
@@ -335,13 +383,17 @@ class Utils {
335
383
  }
336
384
  return false;
337
385
  }
338
- static isAPIKeyAuth(authSchema) {
339
- return authSchema.type === "apiKey";
386
+ static isBearerTokenAuth(authScheme) {
387
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
340
388
  }
341
- static isBearerTokenAuth(authSchema) {
342
- return (authSchema.type === "oauth2" ||
343
- authSchema.type === "openIdConnect" ||
344
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
389
+ static isAPIKeyAuth(authScheme) {
390
+ return authScheme.type === "apiKey";
391
+ }
392
+ static isOAuthWithAuthCodeFlow(authScheme) {
393
+ if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
394
+ return true;
395
+ }
396
+ return false;
345
397
  }
346
398
  static getAuthArray(securities, spec) {
347
399
  var _a;
@@ -354,7 +406,7 @@ class Utils {
354
406
  for (const name in security) {
355
407
  const auth = securitySchemas[name];
356
408
  authArray.push({
357
- authSchema: auth,
409
+ authScheme: auth,
358
410
  name: name,
359
411
  });
360
412
  }
@@ -369,18 +421,19 @@ class Utils {
369
421
  static updateFirstLetter(str) {
370
422
  return str.charAt(0).toUpperCase() + str.slice(1);
371
423
  }
372
- static getResponseJson(operationObject) {
424
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
373
425
  var _a, _b;
374
426
  let json = {};
375
427
  for (const code of ConstantString.ResponseCodeFor20X) {
376
428
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
377
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
378
- if (mediaTypesCount > 1) {
379
- return {};
380
- }
381
429
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
382
430
  json = responseObject.content["application/json"];
383
- break;
431
+ if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
432
+ json = {};
433
+ }
434
+ else {
435
+ break;
436
+ }
384
437
  }
385
438
  }
386
439
  return json;
@@ -454,7 +507,7 @@ class Utils {
454
507
  }
455
508
  return errors;
456
509
  }
457
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
510
+ static validateServer(spec, options) {
458
511
  const errors = [];
459
512
  let hasTopLevelServers = false;
460
513
  let hasPathLevelServers = false;
@@ -475,7 +528,7 @@ class Utils {
475
528
  }
476
529
  for (const method in methods) {
477
530
  const operationObject = methods[method];
478
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
531
+ if (Utils.isSupportedApi(method, path, spec, options)) {
479
532
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
480
533
  hasOperationLevelServers = true;
481
534
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -562,7 +615,7 @@ class Utils {
562
615
  param.value = schema.default;
563
616
  }
564
617
  }
565
- static parseApiInfo(operationItem, allowMultipleParameters) {
618
+ static parseApiInfo(operationItem, options) {
566
619
  var _a, _b;
567
620
  const requiredParams = [];
568
621
  const optionalParams = [];
@@ -576,7 +629,7 @@ class Utils {
576
629
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
577
630
  };
578
631
  const schema = param.schema;
579
- if (allowMultipleParameters && schema) {
632
+ if (options.allowMultipleParameters && schema) {
580
633
  Utils.updateParameterWithInputType(schema, parameter);
581
634
  }
582
635
  if (param.in !== "header" && param.in !== "cookie") {
@@ -594,7 +647,7 @@ class Utils {
594
647
  const requestJson = requestBody.content["application/json"];
595
648
  if (Object.keys(requestJson).length !== 0) {
596
649
  const schema = requestJson.schema;
597
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
650
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
598
651
  requiredParams.push(...requiredP);
599
652
  optionalParams.push(...optionalP);
600
653
  }
@@ -625,14 +678,13 @@ class Utils {
625
678
  }
626
679
  return [command, warning];
627
680
  }
628
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
681
+ static listSupportedAPIs(spec, options) {
629
682
  const paths = spec.paths;
630
683
  const result = {};
631
684
  for (const path in paths) {
632
685
  const methods = paths[path];
633
686
  for (const method in methods) {
634
- // For developer preview, only support GET operation with only 1 parameter without auth
635
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
687
+ if (Utils.isSupportedApi(method, path, spec, options)) {
636
688
  const operationObject = methods[method];
637
689
  result[`${method.toUpperCase()} ${path}`] = operationObject;
638
690
  }
@@ -640,7 +692,7 @@ class Utils {
640
692
  }
641
693
  return result;
642
694
  }
643
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
695
+ static validateSpec(spec, parser, isSwaggerFile, options) {
644
696
  const errors = [];
645
697
  const warnings = [];
646
698
  if (isSwaggerFile) {
@@ -650,7 +702,7 @@ class Utils {
650
702
  });
651
703
  }
652
704
  // Server validation
653
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
705
+ const serverErrors = Utils.validateServer(spec, options);
654
706
  errors.push(...serverErrors);
655
707
  // Remote reference not supported
656
708
  const refPaths = parser.$refs.paths();
@@ -663,7 +715,7 @@ class Utils {
663
715
  });
664
716
  }
665
717
  // No supported API
666
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
718
+ const apiMap = Utils.listSupportedAPIs(spec, options);
667
719
  if (Object.keys(apiMap).length === 0) {
668
720
  errors.push({
669
721
  type: ErrorType.NoSupportedApi,
@@ -733,7 +785,10 @@ class SpecParser {
733
785
  allowSwagger: false,
734
786
  allowAPIKeyAuth: false,
735
787
  allowMultipleParameters: false,
788
+ allowBearerTokenAuth: false,
736
789
  allowOauth2: false,
790
+ allowMethods: ["get", "post"],
791
+ projectType: ProjectType.SME,
737
792
  };
738
793
  this.pathOrSpec = pathOrDoc;
739
794
  this.parser = new SwaggerParser();
@@ -770,7 +825,7 @@ class SpecParser {
770
825
  ],
771
826
  };
772
827
  }
773
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
828
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
774
829
  }
775
830
  catch (err) {
776
831
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -789,7 +844,7 @@ class SpecParser {
789
844
  if (!operationId) {
790
845
  continue;
791
846
  }
792
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options.allowMultipleParameters);
847
+ const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
793
848
  const apiInfo = {
794
849
  method: method,
795
850
  path: path,
@@ -818,12 +873,32 @@ class SpecParser {
818
873
  async list() {
819
874
  throw new Error("Method not implemented.");
820
875
  }
876
+ /**
877
+ * Generate specs according to the filters.
878
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
879
+ */
880
+ // eslint-disable-next-line @typescript-eslint/require-await
881
+ async getFilteredSpecs(filter, signal) {
882
+ throw new Error("Method not implemented.");
883
+ }
884
+ /**
885
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
886
+ * @param manifestPath A file path of the Teams app manifest file to update.
887
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
888
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
889
+ * @param pluginFilePath File path of the api plugin file to generate.
890
+ */
891
+ // eslint-disable-next-line @typescript-eslint/require-await
892
+ async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
893
+ throw new Error("Method not implemented.");
894
+ }
821
895
  /**
822
896
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
823
897
  * @param manifestPath A file path of the Teams app manifest file to update.
824
898
  * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
825
899
  * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
826
900
  * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
901
+ * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
827
902
  */
828
903
  // eslint-disable-next-line @typescript-eslint/require-await
829
904
  async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
@@ -843,11 +918,169 @@ class SpecParser {
843
918
  if (this.apiMap !== undefined) {
844
919
  return this.apiMap;
845
920
  }
846
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
921
+ const result = Utils.listSupportedAPIs(spec, this.options);
847
922
  this.apiMap = result;
848
923
  return result;
849
924
  }
850
925
  }
851
926
 
852
- export { ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
927
+ // Copyright (c) Microsoft Corporation.
928
+ class AdaptiveCardGenerator {
929
+ static generateAdaptiveCard(operationItem) {
930
+ try {
931
+ const json = Utils.getResponseJson(operationItem);
932
+ let cardBody = [];
933
+ let schema = json.schema;
934
+ let jsonPath = "$";
935
+ if (schema && Object.keys(schema).length > 0) {
936
+ jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
937
+ if (jsonPath !== "$") {
938
+ schema = schema.properties[jsonPath];
939
+ }
940
+ cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
941
+ }
942
+ // if no schema, try to use example value
943
+ if (cardBody.length === 0 && (json.examples || json.example)) {
944
+ cardBody = [
945
+ {
946
+ type: ConstantString.TextBlockType,
947
+ text: "${jsonStringify($root)}",
948
+ wrap: true,
949
+ },
950
+ ];
951
+ }
952
+ // if no example value, use default success response
953
+ if (cardBody.length === 0) {
954
+ cardBody = [
955
+ {
956
+ type: ConstantString.TextBlockType,
957
+ text: "success",
958
+ wrap: true,
959
+ },
960
+ ];
961
+ }
962
+ const fullCard = {
963
+ type: ConstantString.AdaptiveCardType,
964
+ $schema: ConstantString.AdaptiveCardSchema,
965
+ version: ConstantString.AdaptiveCardVersion,
966
+ body: cardBody,
967
+ };
968
+ return [fullCard, jsonPath];
969
+ }
970
+ catch (err) {
971
+ throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
972
+ }
973
+ }
974
+ static generateCardFromResponse(schema, name, parentArrayName = "") {
975
+ if (schema.type === "array") {
976
+ // schema.items can be arbitrary object: schema { type: array, items: {} }
977
+ if (Object.keys(schema.items).length === 0) {
978
+ return [
979
+ {
980
+ type: ConstantString.TextBlockType,
981
+ text: name ? `${name}: \${jsonStringify(${name})}` : "result: ${jsonStringify($root)}",
982
+ wrap: true,
983
+ },
984
+ ];
985
+ }
986
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
987
+ const template = {
988
+ type: ConstantString.ContainerType,
989
+ $data: name ? `\${${name}}` : "${$root}",
990
+ items: Array(),
991
+ };
992
+ template.items.push(...obj);
993
+ return [template];
994
+ }
995
+ // some schema may not contain type but contain properties
996
+ if (schema.type === "object" || (!schema.type && schema.properties)) {
997
+ const { properties } = schema;
998
+ const result = [];
999
+ for (const property in properties) {
1000
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
1001
+ result.push(...obj);
1002
+ }
1003
+ if (schema.additionalProperties) {
1004
+ // TODO: better ways to handler warnings.
1005
+ console.warn(ConstantString.AdditionalPropertiesNotSupported);
1006
+ }
1007
+ return result;
1008
+ }
1009
+ if (schema.type === "string" ||
1010
+ schema.type === "integer" ||
1011
+ schema.type === "boolean" ||
1012
+ schema.type === "number") {
1013
+ if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
1014
+ // string in root: "ddd"
1015
+ let text = "result: ${$root}";
1016
+ if (name) {
1017
+ // object { id: "1" }
1018
+ text = `${name}: \${if(${name}, ${name}, 'N/A')}`;
1019
+ if (parentArrayName) {
1020
+ // object types inside array: { tags: ["id": 1, "name": "name"] }
1021
+ text = `${parentArrayName}.${text}`;
1022
+ }
1023
+ }
1024
+ else if (parentArrayName) {
1025
+ // string array: photoUrls: ["1", "2"]
1026
+ text = `${parentArrayName}: ` + "${$data}";
1027
+ }
1028
+ return [
1029
+ {
1030
+ type: ConstantString.TextBlockType,
1031
+ text,
1032
+ wrap: true,
1033
+ },
1034
+ ];
1035
+ }
1036
+ else {
1037
+ if (name) {
1038
+ return [
1039
+ {
1040
+ type: "Image",
1041
+ url: `\${${name}}`,
1042
+ $when: `\${${name} != null}`,
1043
+ },
1044
+ ];
1045
+ }
1046
+ else {
1047
+ return [
1048
+ {
1049
+ type: "Image",
1050
+ url: "${$data}",
1051
+ $when: "${$data != null}",
1052
+ },
1053
+ ];
1054
+ }
1055
+ }
1056
+ }
1057
+ if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
1058
+ throw new Error(Utils.format(ConstantString.SchemaNotSupported, JSON.stringify(schema)));
1059
+ }
1060
+ throw new Error(Utils.format(ConstantString.UnknownSchema, JSON.stringify(schema)));
1061
+ }
1062
+ // Find the first array property in the response schema object with the well-known name
1063
+ static getResponseJsonPathFromSchema(schema) {
1064
+ if (schema.type === "object" || (!schema.type && schema.properties)) {
1065
+ const { properties } = schema;
1066
+ for (const property in properties) {
1067
+ const schema = properties[property];
1068
+ if (schema.type === "array" &&
1069
+ Utils.isWellKnownName(property, ConstantString.WellknownResultNames)) {
1070
+ return property;
1071
+ }
1072
+ }
1073
+ }
1074
+ return "$";
1075
+ }
1076
+ static isImageUrlProperty(schema, name, parentArrayName) {
1077
+ const propertyName = name ? name : parentArrayName;
1078
+ return (!!propertyName &&
1079
+ schema.type === "string" &&
1080
+ Utils.isWellKnownName(propertyName, ConstantString.WellknownImageName) &&
1081
+ (propertyName.toLocaleLowerCase().indexOf("url") >= 0 || schema.format === "uri"));
1082
+ }
1083
+ }
1084
+
1085
+ export { AdaptiveCardGenerator, ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
853
1086
  //# sourceMappingURL=index.esm2017.js.map