@microsoft/m365-spec-parser 0.1.1-alpha.f04ac4ba4.0 → 0.1.1-alpha.f4dd51600.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,8 @@ 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
+ ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
19
20
  ErrorType["ListFailed"] = "list-failed";
20
21
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
21
22
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -24,6 +25,21 @@ var ErrorType;
24
25
  ErrorType["GenerateFailed"] = "generate-failed";
25
26
  ErrorType["ValidateFailed"] = "validate-failed";
26
27
  ErrorType["GetSpecFailed"] = "get-spec-failed";
28
+ ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
29
+ ErrorType["MissingOperationId"] = "missing-operation-id";
30
+ ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
31
+ ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
32
+ ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
33
+ ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
34
+ ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
35
+ ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
36
+ ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
37
+ ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
38
+ ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
39
+ ErrorType["NoParameter"] = "no-parameter";
40
+ ErrorType["NoAPIInfo"] = "no-api-info";
41
+ ErrorType["MethodNotAllowed"] = "method-not-allowed";
42
+ ErrorType["UrlPathNotExist"] = "url-path-not-exist";
27
43
  ErrorType["Cancelled"] = "cancelled";
28
44
  ErrorType["Unknown"] = "unknown";
29
45
  })(ErrorType || (ErrorType = {}));
@@ -79,7 +95,8 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
79
95
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
80
96
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
81
97
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
82
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
98
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
99
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
83
100
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
84
101
  ConstantString.WrappedCardVersion = "devPreview";
85
102
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
@@ -90,8 +107,10 @@ ConstantString.AdaptiveCardVersion = "1.5";
90
107
  ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
91
108
  ConstantString.AdaptiveCardType = "AdaptiveCard";
92
109
  ConstantString.TextBlockType = "TextBlock";
110
+ ConstantString.ImageType = "Image";
93
111
  ConstantString.ContainerType = "Container";
94
112
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
113
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
95
114
  ConstantString.ResponseCodeFor20X = [
96
115
  "200",
97
116
  "201",
@@ -152,7 +171,8 @@ ConstantString.CommandDescriptionMaxLens = 128;
152
171
  ConstantString.ParameterDescriptionMaxLens = 128;
153
172
  ConstantString.CommandTitleMaxLens = 32;
154
173
  ConstantString.ParameterTitleMaxLens = 32;
155
- ConstantString.SMERequiredParamsMaxNum = 5;
174
+ ConstantString.SMERequiredParamsMaxNum = 5;
175
+ ConstantString.DefaultPluginId = "plugin_1";
156
176
 
157
177
  // Copyright (c) Microsoft Corporation.
158
178
  class Utils {
@@ -167,229 +187,19 @@ class Utils {
167
187
  }
168
188
  return false;
169
189
  }
170
- static checkParameters(paramObject, isCopilot) {
171
- const paramResult = {
172
- requiredNum: 0,
173
- optionalNum: 0,
174
- isValid: true,
175
- };
176
- if (!paramObject) {
177
- return paramResult;
178
- }
179
- for (let i = 0; i < paramObject.length; i++) {
180
- const param = paramObject[i];
181
- const schema = param.schema;
182
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
183
- paramResult.isValid = false;
184
- continue;
185
- }
186
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
187
- if (isCopilot) {
188
- if (isRequiredWithoutDefault) {
189
- paramResult.requiredNum = paramResult.requiredNum + 1;
190
- }
191
- else {
192
- paramResult.optionalNum = paramResult.optionalNum + 1;
193
- }
194
- continue;
195
- }
196
- if (param.in === "header" || param.in === "cookie") {
197
- if (isRequiredWithoutDefault) {
198
- paramResult.isValid = false;
199
- }
200
- continue;
201
- }
202
- if (schema.type !== "boolean" &&
203
- schema.type !== "string" &&
204
- schema.type !== "number" &&
205
- schema.type !== "integer") {
206
- if (isRequiredWithoutDefault) {
207
- paramResult.isValid = false;
208
- }
209
- continue;
210
- }
211
- if (param.in === "query" || param.in === "path") {
212
- if (isRequiredWithoutDefault) {
213
- paramResult.requiredNum = paramResult.requiredNum + 1;
214
- }
215
- else {
216
- paramResult.optionalNum = paramResult.optionalNum + 1;
217
- }
218
- }
219
- }
220
- return paramResult;
221
- }
222
- static checkPostBody(schema, isRequired = false, isCopilot = false) {
223
- var _a;
224
- const paramResult = {
225
- requiredNum: 0,
226
- optionalNum: 0,
227
- isValid: true,
228
- };
229
- if (Object.keys(schema).length === 0) {
230
- return paramResult;
231
- }
232
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
233
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
234
- paramResult.isValid = false;
235
- return paramResult;
236
- }
237
- if (schema.type === "string" ||
238
- schema.type === "integer" ||
239
- schema.type === "boolean" ||
240
- schema.type === "number") {
241
- if (isRequiredWithoutDefault) {
242
- paramResult.requiredNum = paramResult.requiredNum + 1;
243
- }
244
- else {
245
- paramResult.optionalNum = paramResult.optionalNum + 1;
246
- }
247
- }
248
- else if (schema.type === "object") {
249
- const { properties } = schema;
250
- for (const property in properties) {
251
- let isRequired = false;
252
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
253
- isRequired = true;
254
- }
255
- const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
256
- paramResult.requiredNum += result.requiredNum;
257
- paramResult.optionalNum += result.optionalNum;
258
- paramResult.isValid = paramResult.isValid && result.isValid;
259
- }
260
- }
261
- else {
262
- if (isRequiredWithoutDefault && !isCopilot) {
263
- paramResult.isValid = false;
264
- }
265
- }
266
- return paramResult;
267
- }
268
- /**
269
- * Checks if the given API is supported.
270
- * @param {string} method - The HTTP method of the API.
271
- * @param {string} path - The path of the API.
272
- * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
273
- * @returns {boolean} - Returns true if the API is supported, false otherwise.
274
- * @description The following APIs are supported:
275
- * 1. only support Get/Post operation without auth property
276
- * 2. parameter inside query or path only support string, number, boolean and integer
277
- * 3. parameter inside post body only support string, number, boolean, integer and object
278
- * 4. request body + required parameters <= 1
279
- * 5. response body should be “application/json” and not empty, and response code should be 20X
280
- * 6. only support request body with “application/json” content type
281
- */
282
- static isSupportedApi(method, path, spec, options) {
283
- var _a;
284
- const pathObj = spec.paths[path];
285
- method = method.toLocaleLowerCase();
286
- if (pathObj) {
287
- if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
288
- const securities = pathObj[method].security;
289
- const authArray = Utils.getAuthArray(securities, spec);
290
- if (!Utils.isSupportedAuth(authArray, options)) {
291
- return false;
292
- }
293
- const operationObject = pathObj[method];
294
- if (!options.allowMissingId && !operationObject.operationId) {
295
- return false;
296
- }
297
- const paramObject = operationObject.parameters;
298
- const requestBody = operationObject.requestBody;
299
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
300
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
301
- if (mediaTypesCount > 1) {
302
- return false;
303
- }
304
- const responseJson = Utils.getResponseJson(operationObject);
305
- if (Object.keys(responseJson).length === 0) {
306
- return false;
307
- }
308
- let requestBodyParamResult = {
309
- requiredNum: 0,
310
- optionalNum: 0,
311
- isValid: true,
312
- };
313
- const isCopilot = options.projectType === ProjectType.Copilot;
314
- if (requestJsonBody) {
315
- const requestBodySchema = requestJsonBody.schema;
316
- if (isCopilot && requestBodySchema.type !== "object") {
317
- return false;
318
- }
319
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
320
- }
321
- if (!requestBodyParamResult.isValid) {
322
- return false;
323
- }
324
- const paramResult = Utils.checkParameters(paramObject, isCopilot);
325
- if (!paramResult.isValid) {
326
- return false;
327
- }
328
- // Copilot support arbitrary parameters
329
- if (isCopilot) {
330
- return true;
331
- }
332
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
333
- if (options.allowMultipleParameters &&
334
- requestBodyParamResult.requiredNum + paramResult.requiredNum <=
335
- ConstantString.SMERequiredParamsMaxNum) {
336
- return true;
337
- }
338
- return false;
339
- }
340
- else if (requestBodyParamResult.requiredNum +
341
- requestBodyParamResult.optionalNum +
342
- paramResult.requiredNum +
343
- paramResult.optionalNum ===
344
- 0) {
345
- return false;
346
- }
347
- else {
348
- return true;
349
- }
350
- }
351
- }
352
- return false;
190
+ static containMultipleMediaTypes(bodyObject) {
191
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
353
192
  }
354
- static isSupportedAuth(authSchemaArray, options) {
355
- if (authSchemaArray.length === 0) {
356
- return true;
357
- }
358
- if (options.allowAPIKeyAuth || options.allowOauth2) {
359
- // Currently we don't support multiple auth in one operation
360
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
361
- return false;
362
- }
363
- for (const auths of authSchemaArray) {
364
- if (auths.length === 1) {
365
- if (!options.allowOauth2 &&
366
- options.allowAPIKeyAuth &&
367
- Utils.isAPIKeyAuth(auths[0].authSchema)) {
368
- return true;
369
- }
370
- else if (!options.allowAPIKeyAuth &&
371
- options.allowOauth2 &&
372
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
373
- return true;
374
- }
375
- else if (options.allowAPIKeyAuth &&
376
- options.allowOauth2 &&
377
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
378
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
379
- return true;
380
- }
381
- }
382
- }
383
- }
384
- return false;
193
+ static isBearerTokenAuth(authScheme) {
194
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
385
195
  }
386
- static isAPIKeyAuth(authSchema) {
387
- return authSchema.type === "apiKey";
196
+ static isAPIKeyAuth(authScheme) {
197
+ return authScheme.type === "apiKey";
388
198
  }
389
- static isBearerTokenAuth(authSchema) {
390
- return (authSchema.type === "oauth2" ||
391
- authSchema.type === "openIdConnect" ||
392
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
199
+ static isOAuthWithAuthCodeFlow(authScheme) {
200
+ return !!(authScheme.type === "oauth2" &&
201
+ authScheme.flows &&
202
+ authScheme.flows.authorizationCode);
393
203
  }
394
204
  static getAuthArray(securities, spec) {
395
205
  var _a;
@@ -402,7 +212,7 @@ class Utils {
402
212
  for (const name in security) {
403
213
  const auth = securitySchemas[name];
404
214
  authArray.push({
405
- authSchema: auth,
215
+ authScheme: auth,
406
216
  name: name,
407
217
  });
408
218
  }
@@ -420,18 +230,22 @@ class Utils {
420
230
  static getResponseJson(operationObject) {
421
231
  var _a, _b;
422
232
  let json = {};
233
+ let multipleMediaType = false;
423
234
  for (const code of ConstantString.ResponseCodeFor20X) {
424
235
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
425
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
426
- if (mediaTypesCount > 1) {
427
- return {};
428
- }
429
236
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
237
+ multipleMediaType = false;
430
238
  json = responseObject.content["application/json"];
431
- break;
239
+ if (Utils.containMultipleMediaTypes(responseObject)) {
240
+ multipleMediaType = true;
241
+ json = {};
242
+ }
243
+ else {
244
+ break;
245
+ }
432
246
  }
433
247
  }
434
- return json;
248
+ return { json, multipleMediaType };
435
249
  }
436
250
  static convertPathToCamelCase(path) {
437
251
  const pathSegments = path.split(/[./{]/);
@@ -451,10 +265,10 @@ class Utils {
451
265
  return undefined;
452
266
  }
453
267
  }
454
- static resolveServerUrl(url) {
268
+ static resolveEnv(str) {
455
269
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
456
- let matches = placeHolderReg.exec(url);
457
- let newUrl = url;
270
+ let matches = placeHolderReg.exec(str);
271
+ let newStr = str;
458
272
  while (matches != null) {
459
273
  const envVar = matches[1];
460
274
  const envVal = process.env[envVar];
@@ -462,17 +276,17 @@ class Utils {
462
276
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
463
277
  }
464
278
  else {
465
- newUrl = newUrl.replace(matches[0], envVal);
279
+ newStr = newStr.replace(matches[0], envVal);
466
280
  }
467
- matches = placeHolderReg.exec(url);
281
+ matches = placeHolderReg.exec(str);
468
282
  }
469
- return newUrl;
283
+ return newStr;
470
284
  }
471
285
  static checkServerUrl(servers) {
472
286
  const errors = [];
473
287
  let serverUrl;
474
288
  try {
475
- serverUrl = Utils.resolveServerUrl(servers[0].url);
289
+ serverUrl = Utils.resolveEnv(servers[0].url);
476
290
  }
477
291
  catch (err) {
478
292
  errors.push({
@@ -503,6 +317,7 @@ class Utils {
503
317
  return errors;
504
318
  }
505
319
  static validateServer(spec, options) {
320
+ var _a;
506
321
  const errors = [];
507
322
  let hasTopLevelServers = false;
508
323
  let hasPathLevelServers = false;
@@ -523,7 +338,7 @@ class Utils {
523
338
  }
524
339
  for (const method in methods) {
525
340
  const operationObject = methods[method];
526
- if (Utils.isSupportedApi(method, path, spec, options)) {
341
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
527
342
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
528
343
  hasOperationLevelServers = true;
529
344
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -566,6 +381,7 @@ class Utils {
566
381
  Utils.updateParameterWithInputType(schema, parameter);
567
382
  }
568
383
  if (isRequired && schema.default === undefined) {
384
+ parameter.isRequired = true;
569
385
  requiredParams.push(parameter);
570
386
  }
571
387
  else {
@@ -629,6 +445,7 @@ class Utils {
629
445
  }
630
446
  if (param.in !== "header" && param.in !== "cookie") {
631
447
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
448
+ parameter.isRequired = true;
632
449
  requiredParams.push(parameter);
633
450
  }
634
451
  else {
@@ -648,13 +465,7 @@ class Utils {
648
465
  }
649
466
  }
650
467
  const operationId = operationItem.operationId;
651
- const parameters = [];
652
- if (requiredParams.length !== 0) {
653
- parameters.push(...requiredParams);
654
- }
655
- else {
656
- parameters.push(optionalParams[0]);
657
- }
468
+ const parameters = [...requiredParams, ...optionalParams];
658
469
  const command = {
659
470
  context: ["compose"],
660
471
  type: "query",
@@ -663,105 +474,535 @@ class Utils {
663
474
  parameters: parameters,
664
475
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
665
476
  };
666
- let warning = undefined;
667
- if (requiredParams.length === 0 && optionalParams.length > 1) {
668
- warning = {
669
- type: WarningType.OperationOnlyContainsOptionalParam,
670
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
671
- data: operationId,
672
- };
477
+ return command;
478
+ }
479
+ static format(str, ...args) {
480
+ let index = 0;
481
+ return str.replace(/%s/g, () => {
482
+ const arg = args[index++];
483
+ return arg !== undefined ? arg : "";
484
+ });
485
+ }
486
+ static getSafeRegistrationIdEnvName(authName) {
487
+ if (!authName) {
488
+ return "";
673
489
  }
674
- return [command, warning];
490
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
491
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
492
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
493
+ }
494
+ return safeRegistrationIdEnvName;
675
495
  }
676
- static listSupportedAPIs(spec, options) {
677
- const paths = spec.paths;
496
+ static getServerObject(spec, method, path) {
497
+ const pathObj = spec.paths[path];
498
+ const operationObject = pathObj[method];
499
+ const rootServer = spec.servers && spec.servers[0];
500
+ const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
501
+ const operationServer = operationObject.servers && operationObject.servers[0];
502
+ const serverUrl = operationServer || methodServer || rootServer;
503
+ return serverUrl;
504
+ }
505
+ }
506
+
507
+ // Copyright (c) Microsoft Corporation.
508
+ class Validator {
509
+ listAPIs() {
510
+ var _a;
511
+ if (this.apiMap) {
512
+ return this.apiMap;
513
+ }
514
+ const paths = this.spec.paths;
678
515
  const result = {};
679
516
  for (const path in paths) {
680
517
  const methods = paths[path];
681
518
  for (const method in methods) {
682
- // For developer preview, only support GET operation with only 1 parameter without auth
683
- if (Utils.isSupportedApi(method, path, spec, options)) {
684
- const operationObject = methods[method];
685
- result[`${method.toUpperCase()} ${path}`] = operationObject;
519
+ const operationObject = methods[method];
520
+ if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
521
+ const validateResult = this.validateAPI(method, path);
522
+ result[`${method.toUpperCase()} ${path}`] = {
523
+ operation: operationObject,
524
+ isValid: validateResult.isValid,
525
+ reason: validateResult.reason,
526
+ };
686
527
  }
687
528
  }
688
529
  }
530
+ this.apiMap = result;
689
531
  return result;
690
532
  }
691
- static validateSpec(spec, parser, isSwaggerFile, options) {
692
- const errors = [];
693
- const warnings = [];
694
- if (isSwaggerFile) {
695
- warnings.push({
696
- type: WarningType.ConvertSwaggerToOpenAPI,
697
- content: ConstantString.ConvertSwaggerToOpenAPI,
698
- });
699
- }
700
- // Server validation
701
- const serverErrors = Utils.validateServer(spec, options);
702
- errors.push(...serverErrors);
703
- // Remote reference not supported
704
- const refPaths = parser.$refs.paths();
705
- // refPaths [0] is the current spec file path
706
- if (refPaths.length > 1) {
707
- errors.push({
708
- type: ErrorType.RemoteRefNotSupported,
709
- content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
710
- data: refPaths,
533
+ validateSpecVersion() {
534
+ const result = { errors: [], warnings: [] };
535
+ if (this.spec.openapi >= "3.1.0") {
536
+ result.errors.push({
537
+ type: ErrorType.SpecVersionNotSupported,
538
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
539
+ data: this.spec.openapi,
711
540
  });
712
541
  }
713
- // No supported API
714
- const apiMap = Utils.listSupportedAPIs(spec, options);
715
- if (Object.keys(apiMap).length === 0) {
716
- errors.push({
542
+ return result;
543
+ }
544
+ validateSpecServer() {
545
+ const result = { errors: [], warnings: [] };
546
+ const serverErrors = Utils.validateServer(this.spec, this.options);
547
+ result.errors.push(...serverErrors);
548
+ return result;
549
+ }
550
+ validateSpecNoSupportAPI() {
551
+ const result = { errors: [], warnings: [] };
552
+ const apiMap = this.listAPIs();
553
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
554
+ if (validAPIs.length === 0) {
555
+ const data = [];
556
+ for (const key in apiMap) {
557
+ const { reason } = apiMap[key];
558
+ const apiInvalidReason = { api: key, reason: reason };
559
+ data.push(apiInvalidReason);
560
+ }
561
+ result.errors.push({
717
562
  type: ErrorType.NoSupportedApi,
718
563
  content: ConstantString.NoSupportedApi,
564
+ data,
719
565
  });
720
566
  }
567
+ return result;
568
+ }
569
+ validateSpecOperationId() {
570
+ const result = { errors: [], warnings: [] };
571
+ const apiMap = this.listAPIs();
721
572
  // OperationId missing
722
573
  const apisMissingOperationId = [];
723
574
  for (const key in apiMap) {
724
- const pathObjectItem = apiMap[key];
725
- if (!pathObjectItem.operationId) {
575
+ const { operation } = apiMap[key];
576
+ if (!operation.operationId) {
726
577
  apisMissingOperationId.push(key);
727
578
  }
728
579
  }
729
580
  if (apisMissingOperationId.length > 0) {
730
- warnings.push({
581
+ result.warnings.push({
731
582
  type: WarningType.OperationIdMissing,
732
583
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
733
584
  data: apisMissingOperationId,
734
585
  });
735
586
  }
736
- let status = ValidationStatus.Valid;
737
- if (warnings.length > 0 && errors.length === 0) {
738
- status = ValidationStatus.Warning;
587
+ return result;
588
+ }
589
+ validateMethodAndPath(method, path) {
590
+ const result = { isValid: true, reason: [] };
591
+ if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
592
+ result.isValid = false;
593
+ result.reason.push(ErrorType.MethodNotAllowed);
594
+ return result;
595
+ }
596
+ const pathObj = this.spec.paths[path];
597
+ if (!pathObj || !pathObj[method]) {
598
+ result.isValid = false;
599
+ result.reason.push(ErrorType.UrlPathNotExist);
600
+ return result;
601
+ }
602
+ return result;
603
+ }
604
+ validateResponse(method, path) {
605
+ const result = { isValid: true, reason: [] };
606
+ const operationObject = this.spec.paths[path][method];
607
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
608
+ // only support response body only contains “application/json” content type
609
+ if (multipleMediaType) {
610
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
611
+ }
612
+ else if (Object.keys(json).length === 0) {
613
+ // response body should not be empty
614
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
615
+ }
616
+ return result;
617
+ }
618
+ validateServer(method, path) {
619
+ const result = { isValid: true, reason: [] };
620
+ const serverObj = Utils.getServerObject(this.spec, method, path);
621
+ if (!serverObj) {
622
+ // should contain server URL
623
+ result.reason.push(ErrorType.NoServerInformation);
624
+ }
625
+ else {
626
+ // server url should be absolute url with https protocol
627
+ const serverValidateResult = Utils.checkServerUrl([serverObj]);
628
+ result.reason.push(...serverValidateResult.map((item) => item.type));
739
629
  }
740
- else if (errors.length > 0) {
741
- status = ValidationStatus.Error;
630
+ return result;
631
+ }
632
+ validateAuth(method, path) {
633
+ const pathObj = this.spec.paths[path];
634
+ const operationObject = pathObj[method];
635
+ const securities = operationObject.security;
636
+ const authSchemeArray = Utils.getAuthArray(securities, this.spec);
637
+ if (authSchemeArray.length === 0) {
638
+ return { isValid: true, reason: [] };
742
639
  }
743
- return {
744
- status,
745
- warnings,
746
- errors,
640
+ if (this.options.allowAPIKeyAuth ||
641
+ this.options.allowOauth2 ||
642
+ this.options.allowBearerTokenAuth) {
643
+ // Currently we don't support multiple auth in one operation
644
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
645
+ return {
646
+ isValid: false,
647
+ reason: [ErrorType.MultipleAuthNotSupported],
648
+ };
649
+ }
650
+ for (const auths of authSchemeArray) {
651
+ if (auths.length === 1) {
652
+ if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
653
+ (this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
654
+ (this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
655
+ return { isValid: true, reason: [] };
656
+ }
657
+ }
658
+ }
659
+ }
660
+ return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
661
+ }
662
+ checkPostBodySchema(schema, isRequired = false) {
663
+ var _a;
664
+ const paramResult = {
665
+ requiredNum: 0,
666
+ optionalNum: 0,
667
+ isValid: true,
668
+ reason: [],
747
669
  };
670
+ if (Object.keys(schema).length === 0) {
671
+ return paramResult;
672
+ }
673
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
674
+ const isCopilot = this.projectType === ProjectType.Copilot;
675
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
676
+ paramResult.isValid = false;
677
+ paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
678
+ return paramResult;
679
+ }
680
+ if (schema.type === "string" ||
681
+ schema.type === "integer" ||
682
+ schema.type === "boolean" ||
683
+ schema.type === "number") {
684
+ if (isRequiredWithoutDefault) {
685
+ paramResult.requiredNum = paramResult.requiredNum + 1;
686
+ }
687
+ else {
688
+ paramResult.optionalNum = paramResult.optionalNum + 1;
689
+ }
690
+ }
691
+ else if (schema.type === "object") {
692
+ const { properties } = schema;
693
+ for (const property in properties) {
694
+ let isRequired = false;
695
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
696
+ isRequired = true;
697
+ }
698
+ const result = this.checkPostBodySchema(properties[property], isRequired);
699
+ paramResult.requiredNum += result.requiredNum;
700
+ paramResult.optionalNum += result.optionalNum;
701
+ paramResult.isValid = paramResult.isValid && result.isValid;
702
+ paramResult.reason.push(...result.reason);
703
+ }
704
+ }
705
+ else {
706
+ if (isRequiredWithoutDefault && !isCopilot) {
707
+ paramResult.isValid = false;
708
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
709
+ }
710
+ }
711
+ return paramResult;
748
712
  }
749
- static format(str, ...args) {
750
- let index = 0;
751
- return str.replace(/%s/g, () => {
752
- const arg = args[index++];
753
- return arg !== undefined ? arg : "";
754
- });
713
+ checkParamSchema(paramObject) {
714
+ const paramResult = {
715
+ requiredNum: 0,
716
+ optionalNum: 0,
717
+ isValid: true,
718
+ reason: [],
719
+ };
720
+ if (!paramObject) {
721
+ return paramResult;
722
+ }
723
+ const isCopilot = this.projectType === ProjectType.Copilot;
724
+ for (let i = 0; i < paramObject.length; i++) {
725
+ const param = paramObject[i];
726
+ const schema = param.schema;
727
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
728
+ paramResult.isValid = false;
729
+ paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
730
+ continue;
731
+ }
732
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
733
+ if (isCopilot) {
734
+ if (isRequiredWithoutDefault) {
735
+ paramResult.requiredNum = paramResult.requiredNum + 1;
736
+ }
737
+ else {
738
+ paramResult.optionalNum = paramResult.optionalNum + 1;
739
+ }
740
+ continue;
741
+ }
742
+ if (param.in === "header" || param.in === "cookie") {
743
+ if (isRequiredWithoutDefault) {
744
+ paramResult.isValid = false;
745
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
746
+ }
747
+ continue;
748
+ }
749
+ if (schema.type !== "boolean" &&
750
+ schema.type !== "string" &&
751
+ schema.type !== "number" &&
752
+ schema.type !== "integer") {
753
+ if (isRequiredWithoutDefault) {
754
+ paramResult.isValid = false;
755
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
756
+ }
757
+ continue;
758
+ }
759
+ if (param.in === "query" || param.in === "path") {
760
+ if (isRequiredWithoutDefault) {
761
+ paramResult.requiredNum = paramResult.requiredNum + 1;
762
+ }
763
+ else {
764
+ paramResult.optionalNum = paramResult.optionalNum + 1;
765
+ }
766
+ }
767
+ }
768
+ return paramResult;
755
769
  }
756
- static getSafeRegistrationIdEnvName(authName) {
757
- if (!authName) {
758
- return "";
770
+ hasNestedObjectInSchema(schema) {
771
+ if (schema.type === "object") {
772
+ for (const property in schema.properties) {
773
+ const nestedSchema = schema.properties[property];
774
+ if (nestedSchema.type === "object") {
775
+ return true;
776
+ }
777
+ }
759
778
  }
760
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
761
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
762
- safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
779
+ return false;
780
+ }
781
+ }
782
+
783
+ // Copyright (c) Microsoft Corporation.
784
+ class CopilotValidator extends Validator {
785
+ constructor(spec, options) {
786
+ super();
787
+ this.projectType = ProjectType.Copilot;
788
+ this.options = options;
789
+ this.spec = spec;
790
+ }
791
+ validateSpec() {
792
+ const result = { errors: [], warnings: [] };
793
+ // validate spec version
794
+ let validationResult = this.validateSpecVersion();
795
+ result.errors.push(...validationResult.errors);
796
+ // validate spec server
797
+ validationResult = this.validateSpecServer();
798
+ result.errors.push(...validationResult.errors);
799
+ // validate no supported API
800
+ validationResult = this.validateSpecNoSupportAPI();
801
+ result.errors.push(...validationResult.errors);
802
+ // validate operationId missing
803
+ validationResult = this.validateSpecOperationId();
804
+ result.warnings.push(...validationResult.warnings);
805
+ return result;
806
+ }
807
+ validateAPI(method, path) {
808
+ const result = { isValid: true, reason: [] };
809
+ method = method.toLocaleLowerCase();
810
+ // validate method and path
811
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
812
+ if (!methodAndPathResult.isValid) {
813
+ return methodAndPathResult;
814
+ }
815
+ const operationObject = this.spec.paths[path][method];
816
+ // validate auth
817
+ const authCheckResult = this.validateAuth(method, path);
818
+ result.reason.push(...authCheckResult.reason);
819
+ // validate operationId
820
+ if (!this.options.allowMissingId && !operationObject.operationId) {
821
+ result.reason.push(ErrorType.MissingOperationId);
822
+ }
823
+ // validate server
824
+ const validateServerResult = this.validateServer(method, path);
825
+ result.reason.push(...validateServerResult.reason);
826
+ // validate response
827
+ const validateResponseResult = this.validateResponse(method, path);
828
+ result.reason.push(...validateResponseResult.reason);
829
+ // validate requestBody
830
+ const requestBody = operationObject.requestBody;
831
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
832
+ if (Utils.containMultipleMediaTypes(requestBody)) {
833
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
834
+ }
835
+ if (requestJsonBody) {
836
+ const requestBodySchema = requestJsonBody.schema;
837
+ if (requestBodySchema.type !== "object") {
838
+ result.reason.push(ErrorType.PostBodySchemaIsNotJson);
839
+ }
840
+ const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
841
+ result.reason.push(...requestBodyParamResult.reason);
842
+ }
843
+ // validate parameters
844
+ const paramObject = operationObject.parameters;
845
+ const paramResult = this.checkParamSchema(paramObject);
846
+ result.reason.push(...paramResult.reason);
847
+ if (result.reason.length > 0) {
848
+ result.isValid = false;
849
+ }
850
+ return result;
851
+ }
852
+ }
853
+
854
+ // Copyright (c) Microsoft Corporation.
855
+ class SMEValidator extends Validator {
856
+ constructor(spec, options) {
857
+ super();
858
+ this.projectType = ProjectType.SME;
859
+ this.options = options;
860
+ this.spec = spec;
861
+ }
862
+ validateSpec() {
863
+ const result = { errors: [], warnings: [] };
864
+ // validate spec version
865
+ let validationResult = this.validateSpecVersion();
866
+ result.errors.push(...validationResult.errors);
867
+ // validate spec server
868
+ validationResult = this.validateSpecServer();
869
+ result.errors.push(...validationResult.errors);
870
+ // validate no supported API
871
+ validationResult = this.validateSpecNoSupportAPI();
872
+ result.errors.push(...validationResult.errors);
873
+ // validate operationId missing
874
+ if (this.options.allowMissingId) {
875
+ validationResult = this.validateSpecOperationId();
876
+ result.warnings.push(...validationResult.warnings);
877
+ }
878
+ return result;
879
+ }
880
+ validateAPI(method, path) {
881
+ const result = { isValid: true, reason: [] };
882
+ method = method.toLocaleLowerCase();
883
+ // validate method and path
884
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
885
+ if (!methodAndPathResult.isValid) {
886
+ return methodAndPathResult;
887
+ }
888
+ const operationObject = this.spec.paths[path][method];
889
+ // validate auth
890
+ const authCheckResult = this.validateAuth(method, path);
891
+ result.reason.push(...authCheckResult.reason);
892
+ // validate operationId
893
+ if (!this.options.allowMissingId && !operationObject.operationId) {
894
+ result.reason.push(ErrorType.MissingOperationId);
895
+ }
896
+ // validate server
897
+ const validateServerResult = this.validateServer(method, path);
898
+ result.reason.push(...validateServerResult.reason);
899
+ // validate response
900
+ const validateResponseResult = this.validateResponse(method, path);
901
+ result.reason.push(...validateResponseResult.reason);
902
+ let postBodyResult = {
903
+ requiredNum: 0,
904
+ optionalNum: 0,
905
+ isValid: true,
906
+ reason: [],
907
+ };
908
+ // validate requestBody
909
+ const requestBody = operationObject.requestBody;
910
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
911
+ if (Utils.containMultipleMediaTypes(requestBody)) {
912
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
913
+ }
914
+ if (requestJsonBody) {
915
+ const requestBodySchema = requestJsonBody.schema;
916
+ postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
917
+ result.reason.push(...postBodyResult.reason);
918
+ }
919
+ // validate parameters
920
+ const paramObject = operationObject.parameters;
921
+ const paramResult = this.checkParamSchema(paramObject);
922
+ result.reason.push(...paramResult.reason);
923
+ // validate total parameters count
924
+ if (paramResult.isValid && postBodyResult.isValid) {
925
+ const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
926
+ result.reason.push(...paramCountResult.reason);
927
+ }
928
+ if (result.reason.length > 0) {
929
+ result.isValid = false;
930
+ }
931
+ return result;
932
+ }
933
+ validateParamCount(postBodyResult, paramResult) {
934
+ const result = { isValid: true, reason: [] };
935
+ const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
936
+ const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
937
+ if (totalRequiredParams > 1) {
938
+ if (!this.options.allowMultipleParameters ||
939
+ totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
940
+ result.reason.push(ErrorType.ExceededRequiredParamsLimit);
941
+ }
942
+ }
943
+ else if (totalParams === 0) {
944
+ result.reason.push(ErrorType.NoParameter);
945
+ }
946
+ return result;
947
+ }
948
+ }
949
+ SMEValidator.SMERequiredParamsMaxNum = 5;
950
+
951
+ // Copyright (c) Microsoft Corporation.
952
+ class TeamsAIValidator extends Validator {
953
+ constructor(spec, options) {
954
+ super();
955
+ this.projectType = ProjectType.TeamsAi;
956
+ this.options = options;
957
+ this.spec = spec;
958
+ }
959
+ validateSpec() {
960
+ const result = { errors: [], warnings: [] };
961
+ // validate spec server
962
+ let validationResult = this.validateSpecServer();
963
+ result.errors.push(...validationResult.errors);
964
+ // validate no supported API
965
+ validationResult = this.validateSpecNoSupportAPI();
966
+ result.errors.push(...validationResult.errors);
967
+ return result;
968
+ }
969
+ validateAPI(method, path) {
970
+ const result = { isValid: true, reason: [] };
971
+ method = method.toLocaleLowerCase();
972
+ // validate method and path
973
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
974
+ if (!methodAndPathResult.isValid) {
975
+ return methodAndPathResult;
976
+ }
977
+ const operationObject = this.spec.paths[path][method];
978
+ // validate operationId
979
+ if (!this.options.allowMissingId && !operationObject.operationId) {
980
+ result.reason.push(ErrorType.MissingOperationId);
981
+ }
982
+ // validate server
983
+ const validateServerResult = this.validateServer(method, path);
984
+ result.reason.push(...validateServerResult.reason);
985
+ if (result.reason.length > 0) {
986
+ result.isValid = false;
987
+ }
988
+ return result;
989
+ }
990
+ }
991
+
992
+ class ValidatorFactory {
993
+ static create(spec, options) {
994
+ var _a;
995
+ const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : ProjectType.SME;
996
+ switch (type) {
997
+ case ProjectType.SME:
998
+ return new SMEValidator(spec, options);
999
+ case ProjectType.Copilot:
1000
+ return new CopilotValidator(spec, options);
1001
+ case ProjectType.TeamsAi:
1002
+ return new TeamsAIValidator(spec, options);
1003
+ default:
1004
+ throw new Error(`Invalid project type: ${type}`);
763
1005
  }
764
- return safeRegistrationIdEnvName;
765
1006
  }
766
1007
  }
767
1008
 
@@ -781,8 +1022,11 @@ class SpecParser {
781
1022
  allowSwagger: false,
782
1023
  allowAPIKeyAuth: false,
783
1024
  allowMultipleParameters: false,
1025
+ allowBearerTokenAuth: false,
784
1026
  allowOauth2: false,
785
1027
  allowMethods: ["get", "post"],
1028
+ allowConversationStarters: false,
1029
+ allowResponseSemantics: false,
786
1030
  projectType: ProjectType.SME,
787
1031
  };
788
1032
  this.pathOrSpec = pathOrDoc;
@@ -798,11 +1042,7 @@ class SpecParser {
798
1042
  try {
799
1043
  try {
800
1044
  await this.loadSpec();
801
- await this.parser.validate(this.spec, {
802
- validate: {
803
- schema: false,
804
- },
805
- });
1045
+ await this.parser.validate(this.spec);
806
1046
  }
807
1047
  catch (e) {
808
1048
  return {
@@ -811,16 +1051,46 @@ class SpecParser {
811
1051
  errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
812
1052
  };
813
1053
  }
1054
+ const errors = [];
1055
+ const warnings = [];
814
1056
  if (!this.options.allowSwagger && this.isSwaggerFile) {
815
1057
  return {
816
1058
  status: ValidationStatus.Error,
817
1059
  warnings: [],
818
1060
  errors: [
819
- { type: ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1061
+ {
1062
+ type: ErrorType.SwaggerNotSupported,
1063
+ content: ConstantString.SwaggerNotSupported,
1064
+ },
820
1065
  ],
821
1066
  };
822
1067
  }
823
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1068
+ // Remote reference not supported
1069
+ const refPaths = this.parser.$refs.paths();
1070
+ // refPaths [0] is the current spec file path
1071
+ if (refPaths.length > 1) {
1072
+ errors.push({
1073
+ type: ErrorType.RemoteRefNotSupported,
1074
+ content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
1075
+ data: refPaths,
1076
+ });
1077
+ }
1078
+ const validator = this.getValidator(this.spec);
1079
+ const validationResult = validator.validateSpec();
1080
+ warnings.push(...validationResult.warnings);
1081
+ errors.push(...validationResult.errors);
1082
+ let status = ValidationStatus.Valid;
1083
+ if (warnings.length > 0 && errors.length === 0) {
1084
+ status = ValidationStatus.Warning;
1085
+ }
1086
+ else if (errors.length > 0) {
1087
+ status = ValidationStatus.Error;
1088
+ }
1089
+ return {
1090
+ status: status,
1091
+ warnings: warnings,
1092
+ errors: errors,
1093
+ };
824
1094
  }
825
1095
  catch (err) {
826
1096
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -829,17 +1099,20 @@ class SpecParser {
829
1099
  async listSupportedAPIInfo() {
830
1100
  try {
831
1101
  await this.loadSpec();
832
- const apiMap = this.getAllSupportedAPIs(this.spec);
1102
+ const apiMap = this.getAPIs(this.spec);
833
1103
  const apiInfos = [];
834
1104
  for (const key in apiMap) {
835
- const pathObjectItem = apiMap[key];
1105
+ const { operation, isValid } = apiMap[key];
1106
+ if (!isValid) {
1107
+ continue;
1108
+ }
836
1109
  const [method, path] = key.split(" ");
837
- const operationId = pathObjectItem.operationId;
1110
+ const operationId = operation.operationId;
838
1111
  // In Browser environment, this api is by default not support api without operationId
839
1112
  if (!operationId) {
840
1113
  continue;
841
1114
  }
842
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
1115
+ const command = Utils.parseApiInfo(operation, this.options);
843
1116
  const apiInfo = {
844
1117
  method: method,
845
1118
  path: path,
@@ -848,9 +1121,6 @@ class SpecParser {
848
1121
  parameters: command.parameters,
849
1122
  description: command.description,
850
1123
  };
851
- if (warning) {
852
- apiInfo.warning = warning;
853
- }
854
1124
  apiInfos.push(apiInfo);
855
1125
  }
856
1126
  return apiInfos;
@@ -909,13 +1179,18 @@ class SpecParser {
909
1179
  this.spec = (await this.parser.dereference(clonedUnResolveSpec));
910
1180
  }
911
1181
  }
912
- getAllSupportedAPIs(spec) {
913
- if (this.apiMap !== undefined) {
914
- return this.apiMap;
1182
+ getAPIs(spec) {
1183
+ const validator = this.getValidator(spec);
1184
+ const apiMap = validator.listAPIs();
1185
+ return apiMap;
1186
+ }
1187
+ getValidator(spec) {
1188
+ if (this.validator) {
1189
+ return this.validator;
915
1190
  }
916
- const result = Utils.listSupportedAPIs(spec, this.options);
917
- this.apiMap = result;
918
- return result;
1191
+ const validator = ValidatorFactory.create(spec, this.options);
1192
+ this.validator = validator;
1193
+ return validator;
919
1194
  }
920
1195
  }
921
1196
 
@@ -923,7 +1198,7 @@ class SpecParser {
923
1198
  class AdaptiveCardGenerator {
924
1199
  static generateAdaptiveCard(operationItem) {
925
1200
  try {
926
- const json = Utils.getResponseJson(operationItem);
1201
+ const { json } = Utils.getResponseJson(operationItem);
927
1202
  let cardBody = [];
928
1203
  let schema = json.schema;
929
1204
  let jsonPath = "$";