@microsoft/m365-spec-parser 0.0.2-alpha.2 → 0.1.1-alpha.0de595af8.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.
@@ -19,7 +19,8 @@ var ErrorType;
19
19
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
20
20
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
21
21
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
22
- ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
22
+ ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
23
+ ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
23
24
  ErrorType["ListFailed"] = "list-failed";
24
25
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
25
26
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -27,6 +28,22 @@ var ErrorType;
27
28
  ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
28
29
  ErrorType["GenerateFailed"] = "generate-failed";
29
30
  ErrorType["ValidateFailed"] = "validate-failed";
31
+ ErrorType["GetSpecFailed"] = "get-spec-failed";
32
+ ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
33
+ ErrorType["MissingOperationId"] = "missing-operation-id";
34
+ ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
35
+ ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
36
+ ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
37
+ ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
38
+ ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
39
+ ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
40
+ ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
41
+ ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
42
+ ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
43
+ ErrorType["NoParameter"] = "no-parameter";
44
+ ErrorType["NoAPIInfo"] = "no-api-info";
45
+ ErrorType["MethodNotAllowed"] = "method-not-allowed";
46
+ ErrorType["UrlPathNotExist"] = "url-path-not-exist";
30
47
  ErrorType["Cancelled"] = "cancelled";
31
48
  ErrorType["Unknown"] = "unknown";
32
49
  })(ErrorType || (ErrorType = {}));
@@ -49,7 +66,13 @@ var ValidationStatus;
49
66
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
50
67
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
51
68
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
52
- })(ValidationStatus || (ValidationStatus = {}));
69
+ })(ValidationStatus || (ValidationStatus = {}));
70
+ var ProjectType;
71
+ (function (ProjectType) {
72
+ ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
73
+ ProjectType[ProjectType["SME"] = 1] = "SME";
74
+ ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
75
+ })(ProjectType || (ProjectType = {}));
53
76
 
54
77
  // Copyright (c) Microsoft Corporation.
55
78
  class ConstantString {
@@ -68,7 +91,9 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
68
91
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
69
92
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
70
93
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
71
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
94
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
95
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
96
+ ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
72
97
  ConstantString.WrappedCardVersion = "devPreview";
73
98
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
74
99
  ConstantString.WrappedCardResponseLayout = "list";
@@ -80,6 +105,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
80
105
  ConstantString.TextBlockType = "TextBlock";
81
106
  ConstantString.ContainerType = "Container";
82
107
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
108
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
83
109
  ConstantString.ResponseCodeFor20X = [
84
110
  "200",
85
111
  "201",
@@ -139,7 +165,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
139
165
  ConstantString.CommandDescriptionMaxLens = 128;
140
166
  ConstantString.ParameterDescriptionMaxLens = 128;
141
167
  ConstantString.CommandTitleMaxLens = 32;
142
- ConstantString.ParameterTitleMaxLens = 32;
168
+ ConstantString.ParameterTitleMaxLens = 32;
169
+ ConstantString.SMERequiredParamsMaxNum = 5;
143
170
 
144
171
  // Copyright (c) Microsoft Corporation.
145
172
  class SpecParserError extends Error {
@@ -151,201 +178,30 @@ class SpecParserError extends Error {
151
178
 
152
179
  // Copyright (c) Microsoft Corporation.
153
180
  class Utils {
154
- static checkParameters(paramObject) {
155
- const paramResult = {
156
- requiredNum: 0,
157
- optionalNum: 0,
158
- isValid: true,
159
- };
160
- if (!paramObject) {
161
- return paramResult;
162
- }
163
- for (let i = 0; i < paramObject.length; i++) {
164
- const param = paramObject[i];
165
- const schema = param.schema;
166
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
167
- if (param.in === "header" || param.in === "cookie") {
168
- if (isRequiredWithoutDefault) {
169
- paramResult.isValid = false;
170
- }
171
- continue;
172
- }
173
- if (schema.type !== "boolean" &&
174
- schema.type !== "string" &&
175
- schema.type !== "number" &&
176
- schema.type !== "integer") {
177
- if (isRequiredWithoutDefault) {
178
- paramResult.isValid = false;
179
- }
180
- continue;
181
- }
182
- if (param.in === "query" || param.in === "path") {
183
- if (isRequiredWithoutDefault) {
184
- paramResult.requiredNum = paramResult.requiredNum + 1;
185
- }
186
- else {
187
- paramResult.optionalNum = paramResult.optionalNum + 1;
188
- }
189
- }
190
- }
191
- return paramResult;
192
- }
193
- static checkPostBody(schema, isRequired = false) {
194
- var _a;
195
- const paramResult = {
196
- requiredNum: 0,
197
- optionalNum: 0,
198
- isValid: true,
199
- };
200
- if (Object.keys(schema).length === 0) {
201
- return paramResult;
202
- }
203
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
204
- if (schema.type === "string" ||
205
- schema.type === "integer" ||
206
- schema.type === "boolean" ||
207
- schema.type === "number") {
208
- if (isRequiredWithoutDefault) {
209
- paramResult.requiredNum = paramResult.requiredNum + 1;
210
- }
211
- else {
212
- paramResult.optionalNum = paramResult.optionalNum + 1;
213
- }
214
- }
215
- else if (schema.type === "object") {
216
- const { properties } = schema;
217
- for (const property in properties) {
218
- let isRequired = false;
219
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
220
- isRequired = true;
221
- }
222
- const result = Utils.checkPostBody(properties[property], isRequired);
223
- paramResult.requiredNum += result.requiredNum;
224
- paramResult.optionalNum += result.optionalNum;
225
- paramResult.isValid = paramResult.isValid && result.isValid;
226
- }
227
- }
228
- else {
229
- if (isRequiredWithoutDefault) {
230
- paramResult.isValid = false;
231
- }
232
- }
233
- return paramResult;
234
- }
235
- /**
236
- * Checks if the given API is supported.
237
- * @param {string} method - The HTTP method of the API.
238
- * @param {string} path - The path of the API.
239
- * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
240
- * @returns {boolean} - Returns true if the API is supported, false otherwise.
241
- * @description The following APIs are supported:
242
- * 1. only support Get/Post operation without auth property
243
- * 2. parameter inside query or path only support string, number, boolean and integer
244
- * 3. parameter inside post body only support string, number, boolean, integer and object
245
- * 4. request body + required parameters <= 1
246
- * 5. response body should be “application/json” and not empty, and response code should be 20X
247
- * 6. only support request body with “application/json” content type
248
- */
249
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
250
- const pathObj = spec.paths[path];
251
- method = method.toLocaleLowerCase();
252
- if (pathObj) {
253
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
254
- pathObj[method]) {
255
- const securities = pathObj[method].security;
256
- const authArray = Utils.getAuthArray(securities, spec);
257
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
258
- return false;
259
- }
260
- const operationObject = pathObj[method];
261
- if (!allowMissingId && !operationObject.operationId) {
262
- return false;
263
- }
264
- const paramObject = operationObject.parameters;
265
- const requestBody = operationObject.requestBody;
266
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
267
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
268
- if (mediaTypesCount > 1) {
269
- return false;
270
- }
271
- const responseJson = Utils.getResponseJson(operationObject);
272
- if (Object.keys(responseJson).length === 0) {
273
- return false;
274
- }
275
- let requestBodyParamResult = {
276
- requiredNum: 0,
277
- optionalNum: 0,
278
- isValid: true,
279
- };
280
- if (requestJsonBody) {
281
- const requestBodySchema = requestJsonBody.schema;
282
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
283
- }
284
- if (!requestBodyParamResult.isValid) {
285
- return false;
286
- }
287
- const paramResult = Utils.checkParameters(paramObject);
288
- if (!paramResult.isValid) {
289
- return false;
290
- }
291
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
292
- if (allowMultipleParameters &&
293
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
294
- return true;
295
- }
296
- return false;
297
- }
298
- else if (requestBodyParamResult.requiredNum +
299
- requestBodyParamResult.optionalNum +
300
- paramResult.requiredNum +
301
- paramResult.optionalNum ===
302
- 0) {
303
- return false;
304
- }
305
- else {
181
+ static hasNestedObjectInSchema(schema) {
182
+ if (schema.type === "object") {
183
+ for (const property in schema.properties) {
184
+ const nestedSchema = schema.properties[property];
185
+ if (nestedSchema.type === "object") {
306
186
  return true;
307
187
  }
308
188
  }
309
189
  }
310
190
  return false;
311
191
  }
312
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
313
- if (authSchemaArray.length === 0) {
314
- return true;
315
- }
316
- if (allowAPIKeyAuth || allowOauth2) {
317
- // Currently we don't support multiple auth in one operation
318
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
319
- return false;
320
- }
321
- for (const auths of authSchemaArray) {
322
- if (auths.length === 1) {
323
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
324
- return true;
325
- }
326
- else if (!allowAPIKeyAuth &&
327
- allowOauth2 &&
328
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
329
- return true;
330
- }
331
- else if (allowAPIKeyAuth &&
332
- allowOauth2 &&
333
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
334
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
335
- return true;
336
- }
337
- }
338
- }
339
- }
340
- return false;
192
+ static containMultipleMediaTypes(bodyObject) {
193
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
194
+ }
195
+ static isBearerTokenAuth(authScheme) {
196
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
341
197
  }
342
- static isAPIKeyAuth(authSchema) {
343
- return authSchema.type === "apiKey";
198
+ static isAPIKeyAuth(authScheme) {
199
+ return authScheme.type === "apiKey";
344
200
  }
345
- static isBearerTokenAuth(authSchema) {
346
- return (authSchema.type === "oauth2" ||
347
- authSchema.type === "openIdConnect" ||
348
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
201
+ static isOAuthWithAuthCodeFlow(authScheme) {
202
+ return !!(authScheme.type === "oauth2" &&
203
+ authScheme.flows &&
204
+ authScheme.flows.authorizationCode);
349
205
  }
350
206
  static getAuthArray(securities, spec) {
351
207
  var _a;
@@ -358,7 +214,7 @@ class Utils {
358
214
  for (const name in security) {
359
215
  const auth = securitySchemas[name];
360
216
  authArray.push({
361
- authSchema: auth,
217
+ authScheme: auth,
362
218
  name: name,
363
219
  });
364
220
  }
@@ -376,18 +232,22 @@ class Utils {
376
232
  static getResponseJson(operationObject) {
377
233
  var _a, _b;
378
234
  let json = {};
235
+ let multipleMediaType = false;
379
236
  for (const code of ConstantString.ResponseCodeFor20X) {
380
237
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
381
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
382
- if (mediaTypesCount > 1) {
383
- return {};
384
- }
385
238
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
239
+ multipleMediaType = false;
386
240
  json = responseObject.content["application/json"];
387
- break;
241
+ if (Utils.containMultipleMediaTypes(responseObject)) {
242
+ multipleMediaType = true;
243
+ json = {};
244
+ }
245
+ else {
246
+ break;
247
+ }
388
248
  }
389
249
  }
390
- return json;
250
+ return { json, multipleMediaType };
391
251
  }
392
252
  static convertPathToCamelCase(path) {
393
253
  const pathSegments = path.split(/[./{]/);
@@ -407,10 +267,10 @@ class Utils {
407
267
  return undefined;
408
268
  }
409
269
  }
410
- static resolveServerUrl(url) {
270
+ static resolveEnv(str) {
411
271
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
412
- let matches = placeHolderReg.exec(url);
413
- let newUrl = url;
272
+ let matches = placeHolderReg.exec(str);
273
+ let newStr = str;
414
274
  while (matches != null) {
415
275
  const envVar = matches[1];
416
276
  const envVal = process.env[envVar];
@@ -418,17 +278,17 @@ class Utils {
418
278
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
419
279
  }
420
280
  else {
421
- newUrl = newUrl.replace(matches[0], envVal);
281
+ newStr = newStr.replace(matches[0], envVal);
422
282
  }
423
- matches = placeHolderReg.exec(url);
283
+ matches = placeHolderReg.exec(str);
424
284
  }
425
- return newUrl;
285
+ return newStr;
426
286
  }
427
287
  static checkServerUrl(servers) {
428
288
  const errors = [];
429
289
  let serverUrl;
430
290
  try {
431
- serverUrl = Utils.resolveServerUrl(servers[0].url);
291
+ serverUrl = Utils.resolveEnv(servers[0].url);
432
292
  }
433
293
  catch (err) {
434
294
  errors.push({
@@ -458,7 +318,8 @@ class Utils {
458
318
  }
459
319
  return errors;
460
320
  }
461
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
321
+ static validateServer(spec, options) {
322
+ var _a;
462
323
  const errors = [];
463
324
  let hasTopLevelServers = false;
464
325
  let hasPathLevelServers = false;
@@ -479,7 +340,7 @@ class Utils {
479
340
  }
480
341
  for (const method in methods) {
481
342
  const operationObject = methods[method];
482
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
343
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
483
344
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
484
345
  hasOperationLevelServers = true;
485
346
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -522,6 +383,7 @@ class Utils {
522
383
  Utils.updateParameterWithInputType(schema, parameter);
523
384
  }
524
385
  if (isRequired && schema.default === undefined) {
386
+ parameter.isRequired = true;
525
387
  requiredParams.push(parameter);
526
388
  }
527
389
  else {
@@ -566,7 +428,7 @@ class Utils {
566
428
  param.value = schema.default;
567
429
  }
568
430
  }
569
- static parseApiInfo(operationItem, allowMultipleParameters) {
431
+ static parseApiInfo(operationItem, options) {
570
432
  var _a, _b;
571
433
  const requiredParams = [];
572
434
  const optionalParams = [];
@@ -580,11 +442,12 @@ class Utils {
580
442
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
581
443
  };
582
444
  const schema = param.schema;
583
- if (allowMultipleParameters && schema) {
445
+ if (options.allowMultipleParameters && schema) {
584
446
  Utils.updateParameterWithInputType(schema, parameter);
585
447
  }
586
448
  if (param.in !== "header" && param.in !== "cookie") {
587
449
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
450
+ parameter.isRequired = true;
588
451
  requiredParams.push(parameter);
589
452
  }
590
453
  else {
@@ -598,19 +461,13 @@ class Utils {
598
461
  const requestJson = requestBody.content["application/json"];
599
462
  if (Object.keys(requestJson).length !== 0) {
600
463
  const schema = requestJson.schema;
601
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
464
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
602
465
  requiredParams.push(...requiredP);
603
466
  optionalParams.push(...optionalP);
604
467
  }
605
468
  }
606
469
  const operationId = operationItem.operationId;
607
- const parameters = [];
608
- if (requiredParams.length !== 0) {
609
- parameters.push(...requiredParams);
610
- }
611
- else {
612
- parameters.push(optionalParams[0]);
613
- }
470
+ const parameters = [...requiredParams, ...optionalParams];
614
471
  const command = {
615
472
  context: ["compose"],
616
473
  type: "query",
@@ -619,32 +476,9 @@ class Utils {
619
476
  parameters: parameters,
620
477
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
621
478
  };
622
- let warning = undefined;
623
- if (requiredParams.length === 0 && optionalParams.length > 1) {
624
- warning = {
625
- type: WarningType.OperationOnlyContainsOptionalParam,
626
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
627
- data: operationId,
628
- };
629
- }
630
- return [command, warning];
479
+ return command;
631
480
  }
632
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
633
- const paths = spec.paths;
634
- const result = {};
635
- for (const path in paths) {
636
- const methods = paths[path];
637
- for (const method in methods) {
638
- // For developer preview, only support GET operation with only 1 parameter without auth
639
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
640
- const operationObject = methods[method];
641
- result[`${method.toUpperCase()} ${path}`] = operationObject;
642
- }
643
- }
644
- }
645
- return result;
646
- }
647
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
481
+ static validateSpec(spec, parser, apiMap, isSwaggerFile, options) {
648
482
  const errors = [];
649
483
  const warnings = [];
650
484
  if (isSwaggerFile) {
@@ -653,8 +487,7 @@ class Utils {
653
487
  content: ConstantString.ConvertSwaggerToOpenAPI,
654
488
  });
655
489
  }
656
- // Server validation
657
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
490
+ const serverErrors = Utils.validateServer(spec, options);
658
491
  errors.push(...serverErrors);
659
492
  // Remote reference not supported
660
493
  const refPaths = parser.$refs.paths();
@@ -667,8 +500,8 @@ class Utils {
667
500
  });
668
501
  }
669
502
  // No supported API
670
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
671
- if (Object.keys(apiMap).length === 0) {
503
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
504
+ if (validAPIs.length === 0) {
672
505
  errors.push({
673
506
  type: ErrorType.NoSupportedApi,
674
507
  content: ConstantString.NoSupportedApi,
@@ -677,8 +510,8 @@ class Utils {
677
510
  // OperationId missing
678
511
  const apisMissingOperationId = [];
679
512
  for (const key in apiMap) {
680
- const pathObjectItem = apiMap[key];
681
- if (!pathObjectItem.operationId) {
513
+ const { operation } = apiMap[key];
514
+ if (!operation.operationId) {
682
515
  apisMissingOperationId.push(key);
683
516
  }
684
517
  }
@@ -719,30 +552,434 @@ class Utils {
719
552
  }
720
553
  return safeRegistrationIdEnvName;
721
554
  }
555
+ static getAllAPICount(spec) {
556
+ let count = 0;
557
+ const paths = spec.paths;
558
+ for (const path in paths) {
559
+ const methods = paths[path];
560
+ for (const method in methods) {
561
+ if (ConstantString.AllOperationMethods.includes(method)) {
562
+ count++;
563
+ }
564
+ }
565
+ }
566
+ return count;
567
+ }
568
+ }
569
+
570
+ // Copyright (c) Microsoft Corporation.
571
+ class Validator {
572
+ validateMethodAndPath(method, path) {
573
+ const result = { isValid: true, reason: [] };
574
+ if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
575
+ result.isValid = false;
576
+ result.reason.push(ErrorType.MethodNotAllowed);
577
+ return result;
578
+ }
579
+ const pathObj = this.spec.paths[path];
580
+ if (!pathObj || !pathObj[method]) {
581
+ result.isValid = false;
582
+ result.reason.push(ErrorType.UrlPathNotExist);
583
+ return result;
584
+ }
585
+ return result;
586
+ }
587
+ validateResponse(method, path) {
588
+ const result = { isValid: true, reason: [] };
589
+ const operationObject = this.spec.paths[path][method];
590
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
591
+ // only support response body only contains “application/json” content type
592
+ if (multipleMediaType) {
593
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
594
+ }
595
+ else if (Object.keys(json).length === 0) {
596
+ // response body should not be empty
597
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
598
+ }
599
+ return result;
600
+ }
601
+ validateServer(method, path) {
602
+ const pathObj = this.spec.paths[path];
603
+ const result = { isValid: true, reason: [] };
604
+ const operationObject = pathObj[method];
605
+ const rootServer = this.spec.servers && this.spec.servers[0];
606
+ const methodServer = this.spec.paths[path].servers && this.spec.paths[path].servers[0];
607
+ const operationServer = operationObject.servers && operationObject.servers[0];
608
+ const serverUrl = operationServer || methodServer || rootServer;
609
+ if (!serverUrl) {
610
+ // should contain server URL
611
+ result.reason.push(ErrorType.NoServerInformation);
612
+ }
613
+ else {
614
+ // server url should be absolute url with https protocol
615
+ const serverValidateResult = Utils.checkServerUrl([serverUrl]);
616
+ result.reason.push(...serverValidateResult.map((item) => item.type));
617
+ }
618
+ return result;
619
+ }
620
+ validateAuth(method, path) {
621
+ const pathObj = this.spec.paths[path];
622
+ const operationObject = pathObj[method];
623
+ const securities = operationObject.security;
624
+ const authSchemeArray = Utils.getAuthArray(securities, this.spec);
625
+ if (authSchemeArray.length === 0) {
626
+ return { isValid: true, reason: [] };
627
+ }
628
+ if (this.options.allowAPIKeyAuth ||
629
+ this.options.allowOauth2 ||
630
+ this.options.allowBearerTokenAuth) {
631
+ // Currently we don't support multiple auth in one operation
632
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
633
+ return {
634
+ isValid: false,
635
+ reason: [ErrorType.MultipleAuthNotSupported],
636
+ };
637
+ }
638
+ for (const auths of authSchemeArray) {
639
+ if (auths.length === 1) {
640
+ if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
641
+ (this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
642
+ (this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
643
+ return { isValid: true, reason: [] };
644
+ }
645
+ }
646
+ }
647
+ }
648
+ return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
649
+ }
650
+ checkPostBodySchema(schema, isRequired = false) {
651
+ var _a;
652
+ const paramResult = {
653
+ requiredNum: 0,
654
+ optionalNum: 0,
655
+ isValid: true,
656
+ reason: [],
657
+ };
658
+ if (Object.keys(schema).length === 0) {
659
+ return paramResult;
660
+ }
661
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
662
+ const isCopilot = this.projectType === ProjectType.Copilot;
663
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
664
+ paramResult.isValid = false;
665
+ paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
666
+ return paramResult;
667
+ }
668
+ if (schema.type === "string" ||
669
+ schema.type === "integer" ||
670
+ schema.type === "boolean" ||
671
+ schema.type === "number") {
672
+ if (isRequiredWithoutDefault) {
673
+ paramResult.requiredNum = paramResult.requiredNum + 1;
674
+ }
675
+ else {
676
+ paramResult.optionalNum = paramResult.optionalNum + 1;
677
+ }
678
+ }
679
+ else if (schema.type === "object") {
680
+ const { properties } = schema;
681
+ for (const property in properties) {
682
+ let isRequired = false;
683
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
684
+ isRequired = true;
685
+ }
686
+ const result = this.checkPostBodySchema(properties[property], isRequired);
687
+ paramResult.requiredNum += result.requiredNum;
688
+ paramResult.optionalNum += result.optionalNum;
689
+ paramResult.isValid = paramResult.isValid && result.isValid;
690
+ paramResult.reason.push(...result.reason);
691
+ }
692
+ }
693
+ else {
694
+ if (isRequiredWithoutDefault && !isCopilot) {
695
+ paramResult.isValid = false;
696
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
697
+ }
698
+ }
699
+ return paramResult;
700
+ }
701
+ checkParamSchema(paramObject) {
702
+ const paramResult = {
703
+ requiredNum: 0,
704
+ optionalNum: 0,
705
+ isValid: true,
706
+ reason: [],
707
+ };
708
+ if (!paramObject) {
709
+ return paramResult;
710
+ }
711
+ const isCopilot = this.projectType === ProjectType.Copilot;
712
+ for (let i = 0; i < paramObject.length; i++) {
713
+ const param = paramObject[i];
714
+ const schema = param.schema;
715
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
716
+ paramResult.isValid = false;
717
+ paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
718
+ continue;
719
+ }
720
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
721
+ if (isCopilot) {
722
+ if (isRequiredWithoutDefault) {
723
+ paramResult.requiredNum = paramResult.requiredNum + 1;
724
+ }
725
+ else {
726
+ paramResult.optionalNum = paramResult.optionalNum + 1;
727
+ }
728
+ continue;
729
+ }
730
+ if (param.in === "header" || param.in === "cookie") {
731
+ if (isRequiredWithoutDefault) {
732
+ paramResult.isValid = false;
733
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
734
+ }
735
+ continue;
736
+ }
737
+ if (schema.type !== "boolean" &&
738
+ schema.type !== "string" &&
739
+ schema.type !== "number" &&
740
+ schema.type !== "integer") {
741
+ if (isRequiredWithoutDefault) {
742
+ paramResult.isValid = false;
743
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
744
+ }
745
+ continue;
746
+ }
747
+ if (param.in === "query" || param.in === "path") {
748
+ if (isRequiredWithoutDefault) {
749
+ paramResult.requiredNum = paramResult.requiredNum + 1;
750
+ }
751
+ else {
752
+ paramResult.optionalNum = paramResult.optionalNum + 1;
753
+ }
754
+ }
755
+ }
756
+ return paramResult;
757
+ }
758
+ hasNestedObjectInSchema(schema) {
759
+ if (schema.type === "object") {
760
+ for (const property in schema.properties) {
761
+ const nestedSchema = schema.properties[property];
762
+ if (nestedSchema.type === "object") {
763
+ return true;
764
+ }
765
+ }
766
+ }
767
+ return false;
768
+ }
769
+ }
770
+
771
+ // Copyright (c) Microsoft Corporation.
772
+ class CopilotValidator extends Validator {
773
+ constructor(spec, options) {
774
+ super();
775
+ this.projectType = ProjectType.Copilot;
776
+ this.options = options;
777
+ this.spec = spec;
778
+ }
779
+ validateAPI(method, path) {
780
+ const result = { isValid: true, reason: [] };
781
+ method = method.toLocaleLowerCase();
782
+ // validate method and path
783
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
784
+ if (!methodAndPathResult.isValid) {
785
+ return methodAndPathResult;
786
+ }
787
+ const operationObject = this.spec.paths[path][method];
788
+ // validate auth
789
+ const authCheckResult = this.validateAuth(method, path);
790
+ result.reason.push(...authCheckResult.reason);
791
+ // validate operationId
792
+ if (!this.options.allowMissingId && !operationObject.operationId) {
793
+ result.reason.push(ErrorType.MissingOperationId);
794
+ }
795
+ // validate server
796
+ const validateServerResult = this.validateServer(method, path);
797
+ result.reason.push(...validateServerResult.reason);
798
+ // validate response
799
+ const validateResponseResult = this.validateResponse(method, path);
800
+ result.reason.push(...validateResponseResult.reason);
801
+ // validate requestBody
802
+ const requestBody = operationObject.requestBody;
803
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
804
+ if (Utils.containMultipleMediaTypes(requestBody)) {
805
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
806
+ }
807
+ if (requestJsonBody) {
808
+ const requestBodySchema = requestJsonBody.schema;
809
+ if (requestBodySchema.type !== "object") {
810
+ result.reason.push(ErrorType.PostBodySchemaIsNotJson);
811
+ }
812
+ const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
813
+ result.reason.push(...requestBodyParamResult.reason);
814
+ }
815
+ // validate parameters
816
+ const paramObject = operationObject.parameters;
817
+ const paramResult = this.checkParamSchema(paramObject);
818
+ result.reason.push(...paramResult.reason);
819
+ if (result.reason.length > 0) {
820
+ result.isValid = false;
821
+ }
822
+ return result;
823
+ }
824
+ }
825
+
826
+ // Copyright (c) Microsoft Corporation.
827
+ class SMEValidator extends Validator {
828
+ constructor(spec, options) {
829
+ super();
830
+ this.projectType = ProjectType.SME;
831
+ this.options = options;
832
+ this.spec = spec;
833
+ }
834
+ validateAPI(method, path) {
835
+ const result = { isValid: true, reason: [] };
836
+ method = method.toLocaleLowerCase();
837
+ // validate method and path
838
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
839
+ if (!methodAndPathResult.isValid) {
840
+ return methodAndPathResult;
841
+ }
842
+ const operationObject = this.spec.paths[path][method];
843
+ // validate auth
844
+ const authCheckResult = this.validateAuth(method, path);
845
+ result.reason.push(...authCheckResult.reason);
846
+ // validate operationId
847
+ if (!this.options.allowMissingId && !operationObject.operationId) {
848
+ result.reason.push(ErrorType.MissingOperationId);
849
+ }
850
+ // validate server
851
+ const validateServerResult = this.validateServer(method, path);
852
+ result.reason.push(...validateServerResult.reason);
853
+ // validate response
854
+ const validateResponseResult = this.validateResponse(method, path);
855
+ result.reason.push(...validateResponseResult.reason);
856
+ let postBodyResult = {
857
+ requiredNum: 0,
858
+ optionalNum: 0,
859
+ isValid: true,
860
+ reason: [],
861
+ };
862
+ // validate requestBody
863
+ const requestBody = operationObject.requestBody;
864
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
865
+ if (Utils.containMultipleMediaTypes(requestBody)) {
866
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
867
+ }
868
+ if (requestJsonBody) {
869
+ const requestBodySchema = requestJsonBody.schema;
870
+ postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
871
+ result.reason.push(...postBodyResult.reason);
872
+ }
873
+ // validate parameters
874
+ const paramObject = operationObject.parameters;
875
+ const paramResult = this.checkParamSchema(paramObject);
876
+ result.reason.push(...paramResult.reason);
877
+ // validate total parameters count
878
+ if (paramResult.isValid && postBodyResult.isValid) {
879
+ const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
880
+ result.reason.push(...paramCountResult.reason);
881
+ }
882
+ if (result.reason.length > 0) {
883
+ result.isValid = false;
884
+ }
885
+ return result;
886
+ }
887
+ validateParamCount(postBodyResult, paramResult) {
888
+ const result = { isValid: true, reason: [] };
889
+ const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
890
+ const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
891
+ if (totalRequiredParams > 1) {
892
+ if (!this.options.allowMultipleParameters ||
893
+ totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
894
+ result.reason.push(ErrorType.ExceededRequiredParamsLimit);
895
+ }
896
+ }
897
+ else if (totalParams === 0) {
898
+ result.reason.push(ErrorType.NoParameter);
899
+ }
900
+ return result;
901
+ }
902
+ }
903
+ SMEValidator.SMERequiredParamsMaxNum = 5;
904
+
905
+ // Copyright (c) Microsoft Corporation.
906
+ class TeamsAIValidator extends Validator {
907
+ constructor(spec, options) {
908
+ super();
909
+ this.projectType = ProjectType.TeamsAi;
910
+ this.options = options;
911
+ this.spec = spec;
912
+ }
913
+ validateAPI(method, path) {
914
+ const result = { isValid: true, reason: [] };
915
+ method = method.toLocaleLowerCase();
916
+ // validate method and path
917
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
918
+ if (!methodAndPathResult.isValid) {
919
+ return methodAndPathResult;
920
+ }
921
+ const operationObject = this.spec.paths[path][method];
922
+ // validate operationId
923
+ if (!this.options.allowMissingId && !operationObject.operationId) {
924
+ result.reason.push(ErrorType.MissingOperationId);
925
+ }
926
+ // validate server
927
+ const validateServerResult = this.validateServer(method, path);
928
+ result.reason.push(...validateServerResult.reason);
929
+ if (result.reason.length > 0) {
930
+ result.isValid = false;
931
+ }
932
+ return result;
933
+ }
934
+ }
935
+
936
+ class ValidatorFactory {
937
+ static create(spec, options) {
938
+ var _a;
939
+ const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : ProjectType.SME;
940
+ switch (type) {
941
+ case ProjectType.SME:
942
+ return new SMEValidator(spec, options);
943
+ case ProjectType.Copilot:
944
+ return new CopilotValidator(spec, options);
945
+ case ProjectType.TeamsAi:
946
+ return new TeamsAIValidator(spec, options);
947
+ default:
948
+ throw new Error(`Invalid project type: ${type}`);
949
+ }
950
+ }
722
951
  }
723
952
 
724
953
  // Copyright (c) Microsoft Corporation.
725
954
  class SpecFilter {
726
- static specFilter(filter, unResolveSpec, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
955
+ static specFilter(filter, unResolveSpec, resolvedSpec, options) {
956
+ var _a;
727
957
  try {
728
958
  const newSpec = Object.assign({}, unResolveSpec);
729
959
  const newPaths = {};
730
960
  for (const filterItem of filter) {
731
961
  const [method, path] = filterItem.split(" ");
732
962
  const methodName = method.toLowerCase();
733
- if (!Utils.isSupportedApi(methodName, path, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
734
- continue;
735
- }
736
- if (!newPaths[path]) {
737
- newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
738
- for (const m of ConstantString.AllOperationMethods) {
739
- delete newPaths[path][m];
963
+ const pathObj = (_a = resolvedSpec.paths) === null || _a === void 0 ? void 0 : _a[path];
964
+ if (ConstantString.AllOperationMethods.includes(methodName) &&
965
+ pathObj &&
966
+ pathObj[methodName]) {
967
+ const validator = ValidatorFactory.create(resolvedSpec, options);
968
+ const validateResult = validator.validateAPI(methodName, path);
969
+ if (!validateResult.isValid) {
970
+ continue;
971
+ }
972
+ if (!newPaths[path]) {
973
+ newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
974
+ for (const m of ConstantString.AllOperationMethods) {
975
+ delete newPaths[path][m];
976
+ }
977
+ }
978
+ newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
979
+ // Add the operationId if missing
980
+ if (!newPaths[path][methodName].operationId) {
981
+ newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
740
982
  }
741
- }
742
- newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
743
- // Add the operationId if missing
744
- if (!newPaths[path][methodName].operationId) {
745
- newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
746
983
  }
747
984
  }
748
985
  newSpec.paths = newPaths;
@@ -756,46 +993,168 @@ class SpecFilter {
756
993
 
757
994
  // Copyright (c) Microsoft Corporation.
758
995
  class ManifestUpdater {
759
- static async updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, spec, allowMultipleParameters, auth) {
996
+ static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
997
+ const manifest = await fs.readJSON(manifestPath);
998
+ const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
999
+ manifest.plugins = [
1000
+ {
1001
+ pluginFile: apiPluginRelativePath,
1002
+ },
1003
+ ];
1004
+ const appName = this.removeEnvs(manifest.name.short);
1005
+ ManifestUpdater.updateManifestDescription(manifest, spec);
1006
+ const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
1007
+ const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
1008
+ return [manifest, apiPlugin];
1009
+ }
1010
+ static updateManifestDescription(manifest, spec) {
760
1011
  var _a, _b;
1012
+ manifest.description = {
1013
+ short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
1014
+ full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : manifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
1015
+ };
1016
+ }
1017
+ static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
1018
+ let parameter;
1019
+ if (schema.type === "string" ||
1020
+ schema.type === "boolean" ||
1021
+ schema.type === "integer" ||
1022
+ schema.type === "number" ||
1023
+ schema.type === "array") {
1024
+ parameter = schema;
1025
+ }
1026
+ else {
1027
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
1028
+ }
1029
+ return parameter;
1030
+ }
1031
+ static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
1032
+ var _a, _b, _c;
1033
+ const functions = [];
1034
+ const functionNames = [];
1035
+ const paths = spec.paths;
1036
+ for (const pathUrl in paths) {
1037
+ const pathItem = paths[pathUrl];
1038
+ if (pathItem) {
1039
+ const operations = pathItem;
1040
+ for (const method in operations) {
1041
+ if (options.allowMethods.includes(method)) {
1042
+ const operationItem = operations[method];
1043
+ if (operationItem) {
1044
+ const operationId = operationItem.operationId;
1045
+ const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1046
+ const paramObject = operationItem.parameters;
1047
+ const requestBody = operationItem.requestBody;
1048
+ const parameters = {
1049
+ type: "object",
1050
+ properties: {},
1051
+ required: [],
1052
+ };
1053
+ if (paramObject) {
1054
+ for (let i = 0; i < paramObject.length; i++) {
1055
+ const param = paramObject[i];
1056
+ const schema = param.schema;
1057
+ parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
1058
+ if (param.required) {
1059
+ parameters.required.push(param.name);
1060
+ }
1061
+ if (!parameters.properties[param.name].description) {
1062
+ parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
1063
+ }
1064
+ }
1065
+ }
1066
+ if (requestBody) {
1067
+ const requestJsonBody = requestBody.content["application/json"];
1068
+ const requestBodySchema = requestJsonBody.schema;
1069
+ if (requestBodySchema.type === "object") {
1070
+ if (requestBodySchema.required) {
1071
+ parameters.required.push(...requestBodySchema.required);
1072
+ }
1073
+ for (const property in requestBodySchema.properties) {
1074
+ const schema = requestBodySchema.properties[property];
1075
+ parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
1076
+ }
1077
+ }
1078
+ else {
1079
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
1080
+ }
1081
+ }
1082
+ const funcObj = {
1083
+ name: operationId,
1084
+ description: description,
1085
+ parameters: parameters,
1086
+ };
1087
+ functions.push(funcObj);
1088
+ functionNames.push(operationId);
1089
+ }
1090
+ }
1091
+ }
1092
+ }
1093
+ }
1094
+ const apiPlugin = {
1095
+ schema_version: "v2",
1096
+ name_for_human: appName,
1097
+ description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
1098
+ functions: functions,
1099
+ runtimes: [
1100
+ {
1101
+ type: "OpenApi",
1102
+ auth: {
1103
+ type: "none", // TODO, support auth in the future
1104
+ },
1105
+ spec: {
1106
+ url: specRelativePath,
1107
+ },
1108
+ run_for_functions: functionNames,
1109
+ },
1110
+ ],
1111
+ };
1112
+ return apiPlugin;
1113
+ }
1114
+ static async updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
761
1115
  try {
762
1116
  const originalManifest = await fs.readJSON(manifestPath);
763
1117
  const updatedPart = {};
764
- const [commands, warnings] = await ManifestUpdater.generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters);
765
- const composeExtension = {
766
- composeExtensionType: "apiBased",
767
- apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
768
- commands: commands,
769
- };
770
- if (auth) {
771
- if (Utils.isAPIKeyAuth(auth)) {
772
- auth = auth;
773
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${auth.name}_${ConstantString.RegistrationIdPostfix}`);
774
- composeExtension.authorization = {
775
- authType: "apiSecretServiceAuth",
776
- apiSecretServiceAuthConfiguration: {
777
- apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
778
- },
779
- };
780
- }
781
- else if (Utils.isBearerTokenAuth(auth)) {
782
- composeExtension.authorization = {
783
- authType: "microsoftEntra",
784
- microsoftEntraConfiguration: {
785
- supportsSingleSignOn: true,
786
- },
787
- };
788
- updatedPart.webApplicationInfo = {
789
- id: "${{AAD_APP_CLIENT_ID}}",
790
- resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
791
- };
1118
+ updatedPart.composeExtensions = [];
1119
+ let warnings = [];
1120
+ if (options.projectType === ProjectType.SME) {
1121
+ const updateResult = await ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
1122
+ const commands = updateResult[0];
1123
+ warnings = updateResult[1];
1124
+ const composeExtension = {
1125
+ composeExtensionType: "apiBased",
1126
+ apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
1127
+ commands: commands,
1128
+ };
1129
+ if (authInfo) {
1130
+ const auth = authInfo.authScheme;
1131
+ if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1132
+ const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
1133
+ composeExtension.authorization = {
1134
+ authType: "apiSecretServiceAuth",
1135
+ apiSecretServiceAuthConfiguration: {
1136
+ apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
1137
+ },
1138
+ };
1139
+ }
1140
+ else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
1141
+ const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
1142
+ composeExtension.authorization = {
1143
+ authType: "oAuth2.0",
1144
+ oAuthConfiguration: {
1145
+ oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
1146
+ },
1147
+ };
1148
+ updatedPart.webApplicationInfo = {
1149
+ id: "${{AAD_APP_CLIENT_ID}}",
1150
+ resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
1151
+ };
1152
+ }
792
1153
  }
1154
+ updatedPart.composeExtensions = [composeExtension];
793
1155
  }
794
- updatedPart.description = {
795
- short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
796
- full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : originalManifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
797
- };
798
- updatedPart.composeExtensions = [composeExtension];
1156
+ updatedPart.description = originalManifest.description;
1157
+ ManifestUpdater.updateManifestDescription(updatedPart, spec);
799
1158
  const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
800
1159
  return [updatedManifest, warnings];
801
1160
  }
@@ -803,7 +1162,8 @@ class ManifestUpdater {
803
1162
  throw new SpecParserError(err.toString(), ErrorType.UpdateManifestFailed);
804
1163
  }
805
1164
  }
806
- static async generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters) {
1165
+ static async generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
1166
+ var _a;
807
1167
  const paths = spec.paths;
808
1168
  const commands = [];
809
1169
  const warnings = [];
@@ -814,16 +1174,28 @@ class ManifestUpdater {
814
1174
  const operations = pathItem;
815
1175
  // Currently only support GET and POST method
816
1176
  for (const method in operations) {
817
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1177
+ if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
818
1178
  const operationItem = operations[method];
819
1179
  if (operationItem) {
820
- const [command, warning] = Utils.parseApiInfo(operationItem, allowMultipleParameters);
821
- const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
822
- command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
823
- ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
824
- : "";
825
- if (warning) {
826
- warnings.push(warning);
1180
+ const command = Utils.parseApiInfo(operationItem, options);
1181
+ if (command.parameters &&
1182
+ command.parameters.length >= 1 &&
1183
+ command.parameters.some((param) => param.isRequired)) {
1184
+ command.parameters = command.parameters.filter((param) => param.isRequired);
1185
+ }
1186
+ else if (command.parameters && command.parameters.length > 0) {
1187
+ command.parameters = [command.parameters[0]];
1188
+ warnings.push({
1189
+ type: WarningType.OperationOnlyContainsOptionalParam,
1190
+ content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
1191
+ data: command.id,
1192
+ });
1193
+ }
1194
+ if (adaptiveCardFolder) {
1195
+ const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
1196
+ command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
1197
+ ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
1198
+ : "";
827
1199
  }
828
1200
  commands.push(command);
829
1201
  }
@@ -838,13 +1210,22 @@ class ManifestUpdater {
838
1210
  const relativePath = path.relative(path.dirname(from), to);
839
1211
  return path.normalize(relativePath).replace(/\\/g, "/");
840
1212
  }
1213
+ static removeEnvs(str) {
1214
+ const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
1215
+ const matches = placeHolderReg.exec(str);
1216
+ let newStr = str;
1217
+ if (matches != null) {
1218
+ newStr = newStr.replace(matches[0], "");
1219
+ }
1220
+ return newStr;
1221
+ }
841
1222
  }
842
1223
 
843
1224
  // Copyright (c) Microsoft Corporation.
844
1225
  class AdaptiveCardGenerator {
845
1226
  static generateAdaptiveCard(operationItem) {
846
1227
  try {
847
- const json = Utils.getResponseJson(operationItem);
1228
+ const { json } = Utils.getResponseJson(operationItem);
848
1229
  let cardBody = [];
849
1230
  let schema = json.schema;
850
1231
  let jsonPath = "$";
@@ -1104,8 +1485,11 @@ class SpecParser {
1104
1485
  allowMissingId: true,
1105
1486
  allowSwagger: true,
1106
1487
  allowAPIKeyAuth: false,
1488
+ allowBearerTokenAuth: false,
1107
1489
  allowMultipleParameters: false,
1108
1490
  allowOauth2: false,
1491
+ allowMethods: ["get", "post"],
1492
+ projectType: ProjectType.SME,
1109
1493
  };
1110
1494
  this.pathOrSpec = pathOrDoc;
1111
1495
  this.parser = new SwaggerParser();
@@ -1138,7 +1522,24 @@ class SpecParser {
1138
1522
  ],
1139
1523
  };
1140
1524
  }
1141
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1525
+ if (this.options.projectType === ProjectType.SME ||
1526
+ this.options.projectType === ProjectType.Copilot) {
1527
+ if (this.spec.openapi >= "3.1.0") {
1528
+ return {
1529
+ status: ValidationStatus.Error,
1530
+ warnings: [],
1531
+ errors: [
1532
+ {
1533
+ type: ErrorType.SpecVersionNotSupported,
1534
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
1535
+ data: this.spec.openapi,
1536
+ },
1537
+ ],
1538
+ };
1539
+ }
1540
+ }
1541
+ const apiMap = this.getAPIs(this.spec);
1542
+ return Utils.validateSpec(this.spec, this.parser, apiMap, !!this.isSwaggerFile, this.options);
1142
1543
  }
1143
1544
  catch (err) {
1144
1545
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -1158,16 +1559,22 @@ class SpecParser {
1158
1559
  try {
1159
1560
  await this.loadSpec();
1160
1561
  const spec = this.spec;
1161
- const apiMap = this.getAllSupportedAPIs(spec);
1162
- const result = [];
1562
+ const apiMap = this.getAPIs(spec);
1563
+ const result = {
1564
+ APIs: [],
1565
+ allAPICount: 0,
1566
+ validAPICount: 0,
1567
+ };
1163
1568
  for (const apiKey in apiMap) {
1569
+ const { operation, isValid, reason } = apiMap[apiKey];
1570
+ const [method, path] = apiKey.split(" ");
1164
1571
  const apiResult = {
1165
1572
  api: "",
1166
1573
  server: "",
1167
1574
  operationId: "",
1575
+ isValid: isValid,
1576
+ reason: reason,
1168
1577
  };
1169
- const [method, path] = apiKey.split(" ");
1170
- const operation = apiMap[apiKey];
1171
1578
  const rootServer = spec.servers && spec.servers[0];
1172
1579
  const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
1173
1580
  const operationServer = operation.servers && operation.servers[0];
@@ -1175,7 +1582,7 @@ class SpecParser {
1175
1582
  if (!serverUrl) {
1176
1583
  throw new SpecParserError(ConstantString.NoServerInformation, ErrorType.NoServerInformation);
1177
1584
  }
1178
- apiResult.server = Utils.resolveServerUrl(serverUrl.url);
1585
+ apiResult.server = Utils.resolveEnv(serverUrl.url);
1179
1586
  let operationId = operation.operationId;
1180
1587
  if (!operationId) {
1181
1588
  operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
@@ -1184,13 +1591,15 @@ class SpecParser {
1184
1591
  const authArray = Utils.getAuthArray(operation.security, spec);
1185
1592
  for (const auths of authArray) {
1186
1593
  if (auths.length === 1) {
1187
- apiResult.auth = auths[0].authSchema;
1594
+ apiResult.auth = auths[0];
1188
1595
  break;
1189
1596
  }
1190
1597
  }
1191
1598
  apiResult.api = apiKey;
1192
- result.push(apiResult);
1599
+ result.APIs.push(apiResult);
1193
1600
  }
1601
+ result.allAPICount = result.APIs.length;
1602
+ result.validAPICount = result.APIs.filter((api) => api.isValid).length;
1194
1603
  return result;
1195
1604
  }
1196
1605
  catch (err) {
@@ -1200,48 +1609,108 @@ class SpecParser {
1200
1609
  throw new SpecParserError(err.toString(), ErrorType.ListFailed);
1201
1610
  }
1202
1611
  }
1612
+ /**
1613
+ * Generate specs according to the filters.
1614
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1615
+ */
1616
+ async getFilteredSpecs(filter, signal) {
1617
+ try {
1618
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1619
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1620
+ }
1621
+ await this.loadSpec();
1622
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1623
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1624
+ }
1625
+ const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
1626
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1627
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1628
+ }
1629
+ const newSpec = (await this.parser.dereference(newUnResolvedSpec));
1630
+ return [newUnResolvedSpec, newSpec];
1631
+ }
1632
+ catch (err) {
1633
+ if (err instanceof SpecParserError) {
1634
+ throw err;
1635
+ }
1636
+ throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
1637
+ }
1638
+ }
1203
1639
  /**
1204
1640
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1205
1641
  * @param manifestPath A file path of the Teams app manifest file to update.
1206
1642
  * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1207
1643
  * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1208
- * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1644
+ * @param pluginFilePath File path of the api plugin file to generate.
1209
1645
  */
1210
- async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1646
+ async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1211
1647
  const result = {
1212
1648
  allSuccess: true,
1213
1649
  warnings: [],
1214
1650
  };
1215
1651
  try {
1216
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1217
- throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1652
+ const newSpecs = await this.getFilteredSpecs(filter, signal);
1653
+ const newUnResolvedSpec = newSpecs[0];
1654
+ const newSpec = newSpecs[1];
1655
+ let resultStr;
1656
+ if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1657
+ resultStr = jsyaml.dump(newUnResolvedSpec);
1218
1658
  }
1219
- await this.loadSpec();
1220
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1221
- throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1659
+ else {
1660
+ resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1222
1661
  }
1223
- const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1662
+ await fs.outputFile(outputSpecPath, resultStr);
1224
1663
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1225
1664
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1226
1665
  }
1227
- const newSpec = (await this.parser.dereference(newUnResolvedSpec));
1228
- const AuthSet = new Set();
1229
- let hasMultipleAPIKeyAuth = false;
1666
+ const [updatedManifest, apiPlugin] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
1667
+ await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1668
+ await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
1669
+ }
1670
+ catch (err) {
1671
+ if (err instanceof SpecParserError) {
1672
+ throw err;
1673
+ }
1674
+ throw new SpecParserError(err.toString(), ErrorType.GenerateFailed);
1675
+ }
1676
+ return result;
1677
+ }
1678
+ /**
1679
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1680
+ * @param manifestPath A file path of the Teams app manifest file to update.
1681
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1682
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1683
+ * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1684
+ */
1685
+ async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1686
+ const result = {
1687
+ allSuccess: true,
1688
+ warnings: [],
1689
+ };
1690
+ try {
1691
+ const newSpecs = await this.getFilteredSpecs(filter, signal);
1692
+ const newUnResolvedSpec = newSpecs[0];
1693
+ const newSpec = newSpecs[1];
1694
+ let hasMultipleAuth = false;
1695
+ let authInfo = undefined;
1230
1696
  for (const url in newSpec.paths) {
1231
1697
  for (const method in newSpec.paths[url]) {
1232
1698
  const operation = newSpec.paths[url][method];
1233
1699
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1234
1700
  if (authArray && authArray.length > 0) {
1235
- AuthSet.add(authArray[0][0].authSchema);
1236
- if (AuthSet.size > 1) {
1237
- hasMultipleAPIKeyAuth = true;
1701
+ const currentAuth = authArray[0][0];
1702
+ if (!authInfo) {
1703
+ authInfo = authArray[0][0];
1704
+ }
1705
+ else if (authInfo.name !== currentAuth.name) {
1706
+ hasMultipleAuth = true;
1238
1707
  break;
1239
1708
  }
1240
1709
  }
1241
1710
  }
1242
1711
  }
1243
- if (hasMultipleAPIKeyAuth) {
1244
- throw new SpecParserError(ConstantString.MultipleAPIKeyNotSupported, ErrorType.MultipleAPIKeyNotSupported);
1712
+ if (hasMultipleAuth && this.options.projectType !== ProjectType.TeamsAi) {
1713
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
1245
1714
  }
1246
1715
  let resultStr;
1247
1716
  if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
@@ -1251,26 +1720,28 @@ class SpecParser {
1251
1720
  resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1252
1721
  }
1253
1722
  await fs.outputFile(outputSpecPath, resultStr);
1254
- for (const url in newSpec.paths) {
1255
- for (const method in newSpec.paths[url]) {
1256
- // paths object may contain description/summary, so we need to check if it is a operation object
1257
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1258
- const operation = newSpec.paths[url][method];
1259
- try {
1260
- const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1261
- const fileName = path.join(adaptiveCardFolder, `${operation.operationId}.json`);
1262
- const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1263
- await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
1264
- const dataFileName = path.join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1265
- await fs.outputJSON(dataFileName, {}, { spaces: 2 });
1266
- }
1267
- catch (err) {
1268
- result.allSuccess = false;
1269
- result.warnings.push({
1270
- type: WarningType.GenerateCardFailed,
1271
- content: err.toString(),
1272
- data: operation.operationId,
1273
- });
1723
+ if (adaptiveCardFolder) {
1724
+ for (const url in newSpec.paths) {
1725
+ for (const method in newSpec.paths[url]) {
1726
+ // paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
1727
+ if (this.options.allowMethods.includes(method)) {
1728
+ const operation = newSpec.paths[url][method];
1729
+ try {
1730
+ const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1731
+ const fileName = path.join(adaptiveCardFolder, `${operation.operationId}.json`);
1732
+ const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1733
+ await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
1734
+ const dataFileName = path.join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1735
+ await fs.outputJSON(dataFileName, {}, { spaces: 2 });
1736
+ }
1737
+ catch (err) {
1738
+ result.allSuccess = false;
1739
+ result.warnings.push({
1740
+ type: WarningType.GenerateCardFailed,
1741
+ content: err.toString(),
1742
+ data: operation.operationId,
1743
+ });
1744
+ }
1274
1745
  }
1275
1746
  }
1276
1747
  }
@@ -1278,8 +1749,7 @@ class SpecParser {
1278
1749
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1279
1750
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1280
1751
  }
1281
- const auth = Array.from(AuthSet)[0];
1282
- const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth);
1752
+ const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1283
1753
  await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1284
1754
  result.warnings.push(...warnings);
1285
1755
  }
@@ -1304,15 +1774,36 @@ class SpecParser {
1304
1774
  this.spec = (await this.parser.dereference(clonedUnResolveSpec));
1305
1775
  }
1306
1776
  }
1307
- getAllSupportedAPIs(spec) {
1777
+ getAPIs(spec) {
1308
1778
  if (this.apiMap !== undefined) {
1309
1779
  return this.apiMap;
1310
1780
  }
1311
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1781
+ const result = this.listAPIs(spec, this.options);
1312
1782
  this.apiMap = result;
1313
1783
  return result;
1314
1784
  }
1785
+ listAPIs(spec, options) {
1786
+ var _a;
1787
+ const paths = spec.paths;
1788
+ const result = {};
1789
+ for (const path in paths) {
1790
+ const methods = paths[path];
1791
+ for (const method in methods) {
1792
+ const operationObject = methods[method];
1793
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
1794
+ const validator = ValidatorFactory.create(spec, options);
1795
+ const validateResult = validator.validateAPI(method, path);
1796
+ result[`${method.toUpperCase()} ${path}`] = {
1797
+ operation: operationObject,
1798
+ isValid: validateResult.isValid,
1799
+ reason: validateResult.reason,
1800
+ };
1801
+ }
1802
+ }
1803
+ }
1804
+ return result;
1805
+ }
1315
1806
  }
1316
1807
 
1317
- export { ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
1808
+ export { AdaptiveCardGenerator, ConstantString, ErrorType, ProjectType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
1318
1809
  //# sourceMappingURL=index.esm2017.mjs.map