@microsoft/m365-spec-parser 0.1.1-alpha.d1a09e202.0 → 0.1.1-alpha.ded43fb2d.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.
@@ -46,6 +46,7 @@ var ErrorType;
46
46
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
47
47
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
48
48
  ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
49
+ ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
49
50
  ErrorType["ListFailed"] = "list-failed";
50
51
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
51
52
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -54,6 +55,21 @@ var ErrorType;
54
55
  ErrorType["GenerateFailed"] = "generate-failed";
55
56
  ErrorType["ValidateFailed"] = "validate-failed";
56
57
  ErrorType["GetSpecFailed"] = "get-spec-failed";
58
+ ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
59
+ ErrorType["MissingOperationId"] = "missing-operation-id";
60
+ ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
61
+ ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
62
+ ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
63
+ ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
64
+ ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
65
+ ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
66
+ ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
67
+ ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
68
+ ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
69
+ ErrorType["NoParameter"] = "no-parameter";
70
+ ErrorType["NoAPIInfo"] = "no-api-info";
71
+ ErrorType["MethodNotAllowed"] = "method-not-allowed";
72
+ ErrorType["UrlPathNotExist"] = "url-path-not-exist";
57
73
  ErrorType["Cancelled"] = "cancelled";
58
74
  ErrorType["Unknown"] = "unknown";
59
75
  })(ErrorType || (ErrorType = {}));
@@ -109,6 +125,7 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
109
125
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
110
126
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
111
127
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
128
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
112
129
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
113
130
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
114
131
  ConstantString.WrappedCardVersion = "devPreview";
@@ -120,6 +137,7 @@ ConstantString.AdaptiveCardVersion = "1.5";
120
137
  ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
121
138
  ConstantString.AdaptiveCardType = "AdaptiveCard";
122
139
  ConstantString.TextBlockType = "TextBlock";
140
+ ConstantString.ImageType = "Image";
123
141
  ConstantString.ContainerType = "Container";
124
142
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
125
143
  ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
@@ -183,7 +201,8 @@ ConstantString.CommandDescriptionMaxLens = 128;
183
201
  ConstantString.ParameterDescriptionMaxLens = 128;
184
202
  ConstantString.CommandTitleMaxLens = 32;
185
203
  ConstantString.ParameterTitleMaxLens = 32;
186
- ConstantString.SMERequiredParamsMaxNum = 5;
204
+ ConstantString.SMERequiredParamsMaxNum = 5;
205
+ ConstantString.DefaultPluginId = "plugin_1";
187
206
 
188
207
  // Copyright (c) Microsoft Corporation.
189
208
  class Utils {
@@ -198,221 +217,9 @@ class Utils {
198
217
  }
199
218
  return false;
200
219
  }
201
- static checkParameters(paramObject, isCopilot) {
202
- const paramResult = {
203
- requiredNum: 0,
204
- optionalNum: 0,
205
- isValid: true,
206
- };
207
- if (!paramObject) {
208
- return paramResult;
209
- }
210
- for (let i = 0; i < paramObject.length; i++) {
211
- const param = paramObject[i];
212
- const schema = param.schema;
213
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
214
- paramResult.isValid = false;
215
- continue;
216
- }
217
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
218
- if (isCopilot) {
219
- if (isRequiredWithoutDefault) {
220
- paramResult.requiredNum = paramResult.requiredNum + 1;
221
- }
222
- else {
223
- paramResult.optionalNum = paramResult.optionalNum + 1;
224
- }
225
- continue;
226
- }
227
- if (param.in === "header" || param.in === "cookie") {
228
- if (isRequiredWithoutDefault) {
229
- paramResult.isValid = false;
230
- }
231
- continue;
232
- }
233
- if (schema.type !== "boolean" &&
234
- schema.type !== "string" &&
235
- schema.type !== "number" &&
236
- schema.type !== "integer") {
237
- if (isRequiredWithoutDefault) {
238
- paramResult.isValid = false;
239
- }
240
- continue;
241
- }
242
- if (param.in === "query" || param.in === "path") {
243
- if (isRequiredWithoutDefault) {
244
- paramResult.requiredNum = paramResult.requiredNum + 1;
245
- }
246
- else {
247
- paramResult.optionalNum = paramResult.optionalNum + 1;
248
- }
249
- }
250
- }
251
- return paramResult;
252
- }
253
- static checkPostBody(schema, isRequired = false, isCopilot = false) {
254
- var _a;
255
- const paramResult = {
256
- requiredNum: 0,
257
- optionalNum: 0,
258
- isValid: true,
259
- };
260
- if (Object.keys(schema).length === 0) {
261
- return paramResult;
262
- }
263
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
264
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
265
- paramResult.isValid = false;
266
- return paramResult;
267
- }
268
- if (schema.type === "string" ||
269
- schema.type === "integer" ||
270
- schema.type === "boolean" ||
271
- schema.type === "number") {
272
- if (isRequiredWithoutDefault) {
273
- paramResult.requiredNum = paramResult.requiredNum + 1;
274
- }
275
- else {
276
- paramResult.optionalNum = paramResult.optionalNum + 1;
277
- }
278
- }
279
- else if (schema.type === "object") {
280
- const { properties } = schema;
281
- for (const property in properties) {
282
- let isRequired = false;
283
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
284
- isRequired = true;
285
- }
286
- const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
287
- paramResult.requiredNum += result.requiredNum;
288
- paramResult.optionalNum += result.optionalNum;
289
- paramResult.isValid = paramResult.isValid && result.isValid;
290
- }
291
- }
292
- else {
293
- if (isRequiredWithoutDefault && !isCopilot) {
294
- paramResult.isValid = false;
295
- }
296
- }
297
- return paramResult;
298
- }
299
220
  static containMultipleMediaTypes(bodyObject) {
300
221
  return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
301
222
  }
302
- /**
303
- * Checks if the given API is supported.
304
- * @param {string} method - The HTTP method of the API.
305
- * @param {string} path - The path of the API.
306
- * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
307
- * @returns {boolean} - Returns true if the API is supported, false otherwise.
308
- * @description The following APIs are supported:
309
- * 1. only support Get/Post operation without auth property
310
- * 2. parameter inside query or path only support string, number, boolean and integer
311
- * 3. parameter inside post body only support string, number, boolean, integer and object
312
- * 4. request body + required parameters <= 1
313
- * 5. response body should be “application/json” and not empty, and response code should be 20X
314
- * 6. only support request body with “application/json” content type
315
- */
316
- static isSupportedApi(method, path, spec, options) {
317
- var _a;
318
- const pathObj = spec.paths[path];
319
- method = method.toLocaleLowerCase();
320
- if (pathObj) {
321
- if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
322
- const securities = pathObj[method].security;
323
- const isTeamsAi = options.projectType === ProjectType.TeamsAi;
324
- const isCopilot = options.projectType === ProjectType.Copilot;
325
- // Teams AI project doesn't care about auth, it will use authProvider for user to implement
326
- if (!isTeamsAi) {
327
- const authArray = Utils.getAuthArray(securities, spec);
328
- if (!Utils.isSupportedAuth(authArray, options)) {
329
- return false;
330
- }
331
- }
332
- const operationObject = pathObj[method];
333
- if (!options.allowMissingId && !operationObject.operationId) {
334
- return false;
335
- }
336
- const paramObject = operationObject.parameters;
337
- const requestBody = operationObject.requestBody;
338
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
339
- if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
340
- return false;
341
- }
342
- const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
343
- if (Object.keys(responseJson).length === 0) {
344
- return false;
345
- }
346
- // Teams AI project doesn't care about request parameters/body
347
- if (isTeamsAi) {
348
- return true;
349
- }
350
- let requestBodyParamResult = {
351
- requiredNum: 0,
352
- optionalNum: 0,
353
- isValid: true,
354
- };
355
- if (requestJsonBody) {
356
- const requestBodySchema = requestJsonBody.schema;
357
- if (isCopilot && requestBodySchema.type !== "object") {
358
- return false;
359
- }
360
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
361
- }
362
- if (!requestBodyParamResult.isValid) {
363
- return false;
364
- }
365
- const paramResult = Utils.checkParameters(paramObject, isCopilot);
366
- if (!paramResult.isValid) {
367
- return false;
368
- }
369
- // Copilot support arbitrary parameters
370
- if (isCopilot) {
371
- return true;
372
- }
373
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
374
- if (options.allowMultipleParameters &&
375
- requestBodyParamResult.requiredNum + paramResult.requiredNum <=
376
- ConstantString.SMERequiredParamsMaxNum) {
377
- return true;
378
- }
379
- return false;
380
- }
381
- else if (requestBodyParamResult.requiredNum +
382
- requestBodyParamResult.optionalNum +
383
- paramResult.requiredNum +
384
- paramResult.optionalNum ===
385
- 0) {
386
- return false;
387
- }
388
- else {
389
- return true;
390
- }
391
- }
392
- }
393
- return false;
394
- }
395
- static isSupportedAuth(authSchemeArray, options) {
396
- if (authSchemeArray.length === 0) {
397
- return true;
398
- }
399
- if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
400
- // Currently we don't support multiple auth in one operation
401
- if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
402
- return false;
403
- }
404
- for (const auths of authSchemeArray) {
405
- if (auths.length === 1) {
406
- if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
407
- (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
408
- (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
409
- return true;
410
- }
411
- }
412
- }
413
- }
414
- return false;
415
- }
416
223
  static isBearerTokenAuth(authScheme) {
417
224
  return authScheme.type === "http" && authScheme.scheme === "bearer";
418
225
  }
@@ -420,10 +227,9 @@ class Utils {
420
227
  return authScheme.type === "apiKey";
421
228
  }
422
229
  static isOAuthWithAuthCodeFlow(authScheme) {
423
- if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
424
- return true;
425
- }
426
- return false;
230
+ return !!(authScheme.type === "oauth2" &&
231
+ authScheme.flows &&
232
+ authScheme.flows.authorizationCode);
427
233
  }
428
234
  static getAuthArray(securities, spec) {
429
235
  var _a;
@@ -448,17 +254,39 @@ class Utils {
448
254
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
449
255
  return result;
450
256
  }
257
+ static getAuthInfo(spec) {
258
+ let authInfo = undefined;
259
+ for (const url in spec.paths) {
260
+ for (const method in spec.paths[url]) {
261
+ const operation = spec.paths[url][method];
262
+ const authArray = Utils.getAuthArray(operation.security, spec);
263
+ if (authArray && authArray.length > 0) {
264
+ const currentAuth = authArray[0][0];
265
+ if (!authInfo) {
266
+ authInfo = authArray[0][0];
267
+ }
268
+ else if (authInfo.name !== currentAuth.name) {
269
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
270
+ }
271
+ }
272
+ }
273
+ }
274
+ return authInfo;
275
+ }
451
276
  static updateFirstLetter(str) {
452
277
  return str.charAt(0).toUpperCase() + str.slice(1);
453
278
  }
454
- static getResponseJson(operationObject, isTeamsAiProject = false) {
279
+ static getResponseJson(operationObject) {
455
280
  var _a, _b;
456
281
  let json = {};
282
+ let multipleMediaType = false;
457
283
  for (const code of ConstantString.ResponseCodeFor20X) {
458
284
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
459
285
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
286
+ multipleMediaType = false;
460
287
  json = responseObject.content["application/json"];
461
- if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
288
+ if (Utils.containMultipleMediaTypes(responseObject)) {
289
+ multipleMediaType = true;
462
290
  json = {};
463
291
  }
464
292
  else {
@@ -466,7 +294,7 @@ class Utils {
466
294
  }
467
295
  }
468
296
  }
469
- return json;
297
+ return { json, multipleMediaType };
470
298
  }
471
299
  static convertPathToCamelCase(path) {
472
300
  const pathSegments = path.split(/[./{]/);
@@ -486,10 +314,10 @@ class Utils {
486
314
  return undefined;
487
315
  }
488
316
  }
489
- static resolveServerUrl(url) {
317
+ static resolveEnv(str) {
490
318
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
491
- let matches = placeHolderReg.exec(url);
492
- let newUrl = url;
319
+ let matches = placeHolderReg.exec(str);
320
+ let newStr = str;
493
321
  while (matches != null) {
494
322
  const envVar = matches[1];
495
323
  const envVal = process.env[envVar];
@@ -497,17 +325,17 @@ class Utils {
497
325
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
498
326
  }
499
327
  else {
500
- newUrl = newUrl.replace(matches[0], envVal);
328
+ newStr = newStr.replace(matches[0], envVal);
501
329
  }
502
- matches = placeHolderReg.exec(url);
330
+ matches = placeHolderReg.exec(str);
503
331
  }
504
- return newUrl;
332
+ return newStr;
505
333
  }
506
334
  static checkServerUrl(servers) {
507
335
  const errors = [];
508
336
  let serverUrl;
509
337
  try {
510
- serverUrl = Utils.resolveServerUrl(servers[0].url);
338
+ serverUrl = Utils.resolveEnv(servers[0].url);
511
339
  }
512
340
  catch (err) {
513
341
  errors.push({
@@ -538,6 +366,7 @@ class Utils {
538
366
  return errors;
539
367
  }
540
368
  static validateServer(spec, options) {
369
+ var _a;
541
370
  const errors = [];
542
371
  let hasTopLevelServers = false;
543
372
  let hasPathLevelServers = false;
@@ -558,7 +387,7 @@ class Utils {
558
387
  }
559
388
  for (const method in methods) {
560
389
  const operationObject = methods[method];
561
- if (Utils.isSupportedApi(method, path, spec, options)) {
390
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
562
391
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
563
392
  hasOperationLevelServers = true;
564
393
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -601,6 +430,7 @@ class Utils {
601
430
  Utils.updateParameterWithInputType(schema, parameter);
602
431
  }
603
432
  if (isRequired && schema.default === undefined) {
433
+ parameter.isRequired = true;
604
434
  requiredParams.push(parameter);
605
435
  }
606
436
  else {
@@ -664,6 +494,7 @@ class Utils {
664
494
  }
665
495
  if (param.in !== "header" && param.in !== "cookie") {
666
496
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
497
+ parameter.isRequired = true;
667
498
  requiredParams.push(parameter);
668
499
  }
669
500
  else {
@@ -683,13 +514,7 @@ class Utils {
683
514
  }
684
515
  }
685
516
  const operationId = operationItem.operationId;
686
- const parameters = [];
687
- if (requiredParams.length !== 0) {
688
- parameters.push(...requiredParams);
689
- }
690
- else {
691
- parameters.push(optionalParams[0]);
692
- }
517
+ const parameters = [...requiredParams, ...optionalParams];
693
518
  const command = {
694
519
  context: ["compose"],
695
520
  type: "query",
@@ -698,104 +523,534 @@ class Utils {
698
523
  parameters: parameters,
699
524
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
700
525
  };
701
- let warning = undefined;
702
- if (requiredParams.length === 0 && optionalParams.length > 1) {
703
- warning = {
704
- type: WarningType.OperationOnlyContainsOptionalParam,
705
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
706
- data: operationId,
707
- };
526
+ return command;
527
+ }
528
+ static format(str, ...args) {
529
+ let index = 0;
530
+ return str.replace(/%s/g, () => {
531
+ const arg = args[index++];
532
+ return arg !== undefined ? arg : "";
533
+ });
534
+ }
535
+ static getSafeRegistrationIdEnvName(authName) {
536
+ if (!authName) {
537
+ return "";
708
538
  }
709
- return [command, warning];
539
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
540
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
541
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
542
+ }
543
+ return safeRegistrationIdEnvName;
710
544
  }
711
- static listSupportedAPIs(spec, options) {
712
- const paths = spec.paths;
545
+ static getServerObject(spec, method, path) {
546
+ const pathObj = spec.paths[path];
547
+ const operationObject = pathObj[method];
548
+ const rootServer = spec.servers && spec.servers[0];
549
+ const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
550
+ const operationServer = operationObject.servers && operationObject.servers[0];
551
+ const serverUrl = operationServer || methodServer || rootServer;
552
+ return serverUrl;
553
+ }
554
+ }
555
+
556
+ // Copyright (c) Microsoft Corporation.
557
+ class Validator {
558
+ listAPIs() {
559
+ var _a;
560
+ if (this.apiMap) {
561
+ return this.apiMap;
562
+ }
563
+ const paths = this.spec.paths;
713
564
  const result = {};
714
565
  for (const path in paths) {
715
566
  const methods = paths[path];
716
567
  for (const method in methods) {
717
- if (Utils.isSupportedApi(method, path, spec, options)) {
718
- const operationObject = methods[method];
719
- result[`${method.toUpperCase()} ${path}`] = operationObject;
568
+ const operationObject = methods[method];
569
+ if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
570
+ const validateResult = this.validateAPI(method, path);
571
+ result[`${method.toUpperCase()} ${path}`] = {
572
+ operation: operationObject,
573
+ isValid: validateResult.isValid,
574
+ reason: validateResult.reason,
575
+ };
720
576
  }
721
577
  }
722
578
  }
579
+ this.apiMap = result;
723
580
  return result;
724
581
  }
725
- static validateSpec(spec, parser, isSwaggerFile, options) {
726
- const errors = [];
727
- const warnings = [];
728
- if (isSwaggerFile) {
729
- warnings.push({
730
- type: WarningType.ConvertSwaggerToOpenAPI,
731
- content: ConstantString.ConvertSwaggerToOpenAPI,
582
+ validateSpecVersion() {
583
+ const result = { errors: [], warnings: [] };
584
+ if (this.spec.openapi >= "3.1.0") {
585
+ result.errors.push({
586
+ type: ErrorType.SpecVersionNotSupported,
587
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
588
+ data: this.spec.openapi,
732
589
  });
733
590
  }
734
- // Server validation
735
- const serverErrors = Utils.validateServer(spec, options);
736
- errors.push(...serverErrors);
737
- // Remote reference not supported
738
- const refPaths = parser.$refs.paths();
739
- // refPaths [0] is the current spec file path
740
- if (refPaths.length > 1) {
741
- errors.push({
742
- type: ErrorType.RemoteRefNotSupported,
743
- content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
744
- data: refPaths,
745
- });
746
- }
747
- // No supported API
748
- const apiMap = Utils.listSupportedAPIs(spec, options);
749
- if (Object.keys(apiMap).length === 0) {
750
- errors.push({
591
+ return result;
592
+ }
593
+ validateSpecServer() {
594
+ const result = { errors: [], warnings: [] };
595
+ const serverErrors = Utils.validateServer(this.spec, this.options);
596
+ result.errors.push(...serverErrors);
597
+ return result;
598
+ }
599
+ validateSpecNoSupportAPI() {
600
+ const result = { errors: [], warnings: [] };
601
+ const apiMap = this.listAPIs();
602
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
603
+ if (validAPIs.length === 0) {
604
+ const data = [];
605
+ for (const key in apiMap) {
606
+ const { reason } = apiMap[key];
607
+ const apiInvalidReason = { api: key, reason: reason };
608
+ data.push(apiInvalidReason);
609
+ }
610
+ result.errors.push({
751
611
  type: ErrorType.NoSupportedApi,
752
612
  content: ConstantString.NoSupportedApi,
613
+ data,
753
614
  });
754
615
  }
616
+ return result;
617
+ }
618
+ validateSpecOperationId() {
619
+ const result = { errors: [], warnings: [] };
620
+ const apiMap = this.listAPIs();
755
621
  // OperationId missing
756
622
  const apisMissingOperationId = [];
757
623
  for (const key in apiMap) {
758
- const pathObjectItem = apiMap[key];
759
- if (!pathObjectItem.operationId) {
624
+ const { operation } = apiMap[key];
625
+ if (!operation.operationId) {
760
626
  apisMissingOperationId.push(key);
761
627
  }
762
628
  }
763
629
  if (apisMissingOperationId.length > 0) {
764
- warnings.push({
630
+ result.warnings.push({
765
631
  type: WarningType.OperationIdMissing,
766
632
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
767
633
  data: apisMissingOperationId,
768
634
  });
769
635
  }
770
- let status = ValidationStatus.Valid;
771
- if (warnings.length > 0 && errors.length === 0) {
772
- status = ValidationStatus.Warning;
636
+ return result;
637
+ }
638
+ validateMethodAndPath(method, path) {
639
+ const result = { isValid: true, reason: [] };
640
+ if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
641
+ result.isValid = false;
642
+ result.reason.push(ErrorType.MethodNotAllowed);
643
+ return result;
644
+ }
645
+ const pathObj = this.spec.paths[path];
646
+ if (!pathObj || !pathObj[method]) {
647
+ result.isValid = false;
648
+ result.reason.push(ErrorType.UrlPathNotExist);
649
+ return result;
773
650
  }
774
- else if (errors.length > 0) {
775
- status = ValidationStatus.Error;
651
+ return result;
652
+ }
653
+ validateResponse(method, path) {
654
+ const result = { isValid: true, reason: [] };
655
+ const operationObject = this.spec.paths[path][method];
656
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
657
+ if (this.options.projectType === ProjectType.SME) {
658
+ // only support response body only contains “application/json” content type
659
+ if (multipleMediaType) {
660
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
661
+ }
662
+ else if (Object.keys(json).length === 0) {
663
+ // response body should not be empty
664
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
665
+ }
776
666
  }
777
- return {
778
- status,
779
- warnings,
780
- errors,
667
+ return result;
668
+ }
669
+ validateServer(method, path) {
670
+ const result = { isValid: true, reason: [] };
671
+ const serverObj = Utils.getServerObject(this.spec, method, path);
672
+ if (!serverObj) {
673
+ // should contain server URL
674
+ result.reason.push(ErrorType.NoServerInformation);
675
+ }
676
+ else {
677
+ // server url should be absolute url with https protocol
678
+ const serverValidateResult = Utils.checkServerUrl([serverObj]);
679
+ result.reason.push(...serverValidateResult.map((item) => item.type));
680
+ }
681
+ return result;
682
+ }
683
+ validateAuth(method, path) {
684
+ const pathObj = this.spec.paths[path];
685
+ const operationObject = pathObj[method];
686
+ const securities = operationObject.security;
687
+ const authSchemeArray = Utils.getAuthArray(securities, this.spec);
688
+ if (authSchemeArray.length === 0) {
689
+ return { isValid: true, reason: [] };
690
+ }
691
+ if (this.options.allowAPIKeyAuth ||
692
+ this.options.allowOauth2 ||
693
+ this.options.allowBearerTokenAuth) {
694
+ // Currently we don't support multiple auth in one operation
695
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
696
+ return {
697
+ isValid: false,
698
+ reason: [ErrorType.MultipleAuthNotSupported],
699
+ };
700
+ }
701
+ for (const auths of authSchemeArray) {
702
+ if (auths.length === 1) {
703
+ if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
704
+ (this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
705
+ (this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
706
+ return { isValid: true, reason: [] };
707
+ }
708
+ }
709
+ }
710
+ }
711
+ return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
712
+ }
713
+ checkPostBodySchema(schema, isRequired = false) {
714
+ var _a;
715
+ const paramResult = {
716
+ requiredNum: 0,
717
+ optionalNum: 0,
718
+ isValid: true,
719
+ reason: [],
781
720
  };
721
+ if (Object.keys(schema).length === 0) {
722
+ return paramResult;
723
+ }
724
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
725
+ const isCopilot = this.projectType === ProjectType.Copilot;
726
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
727
+ paramResult.isValid = false;
728
+ paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
729
+ return paramResult;
730
+ }
731
+ if (schema.type === "string" ||
732
+ schema.type === "integer" ||
733
+ schema.type === "boolean" ||
734
+ schema.type === "number") {
735
+ if (isRequiredWithoutDefault) {
736
+ paramResult.requiredNum = paramResult.requiredNum + 1;
737
+ }
738
+ else {
739
+ paramResult.optionalNum = paramResult.optionalNum + 1;
740
+ }
741
+ }
742
+ else if (schema.type === "object") {
743
+ const { properties } = schema;
744
+ for (const property in properties) {
745
+ let isRequired = false;
746
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
747
+ isRequired = true;
748
+ }
749
+ const result = this.checkPostBodySchema(properties[property], isRequired);
750
+ paramResult.requiredNum += result.requiredNum;
751
+ paramResult.optionalNum += result.optionalNum;
752
+ paramResult.isValid = paramResult.isValid && result.isValid;
753
+ paramResult.reason.push(...result.reason);
754
+ }
755
+ }
756
+ else {
757
+ if (isRequiredWithoutDefault && !isCopilot) {
758
+ paramResult.isValid = false;
759
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
760
+ }
761
+ }
762
+ return paramResult;
782
763
  }
783
- static format(str, ...args) {
784
- let index = 0;
785
- return str.replace(/%s/g, () => {
786
- const arg = args[index++];
787
- return arg !== undefined ? arg : "";
788
- });
764
+ checkParamSchema(paramObject) {
765
+ const paramResult = {
766
+ requiredNum: 0,
767
+ optionalNum: 0,
768
+ isValid: true,
769
+ reason: [],
770
+ };
771
+ if (!paramObject) {
772
+ return paramResult;
773
+ }
774
+ const isCopilot = this.projectType === ProjectType.Copilot;
775
+ for (let i = 0; i < paramObject.length; i++) {
776
+ const param = paramObject[i];
777
+ const schema = param.schema;
778
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
779
+ paramResult.isValid = false;
780
+ paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
781
+ continue;
782
+ }
783
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
784
+ if (isCopilot) {
785
+ if (isRequiredWithoutDefault) {
786
+ paramResult.requiredNum = paramResult.requiredNum + 1;
787
+ }
788
+ else {
789
+ paramResult.optionalNum = paramResult.optionalNum + 1;
790
+ }
791
+ continue;
792
+ }
793
+ if (param.in === "header" || param.in === "cookie") {
794
+ if (isRequiredWithoutDefault) {
795
+ paramResult.isValid = false;
796
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
797
+ }
798
+ continue;
799
+ }
800
+ if (schema.type !== "boolean" &&
801
+ schema.type !== "string" &&
802
+ schema.type !== "number" &&
803
+ schema.type !== "integer") {
804
+ if (isRequiredWithoutDefault) {
805
+ paramResult.isValid = false;
806
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
807
+ }
808
+ continue;
809
+ }
810
+ if (param.in === "query" || param.in === "path") {
811
+ if (isRequiredWithoutDefault) {
812
+ paramResult.requiredNum = paramResult.requiredNum + 1;
813
+ }
814
+ else {
815
+ paramResult.optionalNum = paramResult.optionalNum + 1;
816
+ }
817
+ }
818
+ }
819
+ return paramResult;
789
820
  }
790
- static getSafeRegistrationIdEnvName(authName) {
791
- if (!authName) {
792
- return "";
821
+ hasNestedObjectInSchema(schema) {
822
+ if (schema.type === "object") {
823
+ for (const property in schema.properties) {
824
+ const nestedSchema = schema.properties[property];
825
+ if (nestedSchema.type === "object") {
826
+ return true;
827
+ }
828
+ }
793
829
  }
794
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
795
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
796
- safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
830
+ return false;
831
+ }
832
+ }
833
+
834
+ // Copyright (c) Microsoft Corporation.
835
+ class CopilotValidator extends Validator {
836
+ constructor(spec, options) {
837
+ super();
838
+ this.projectType = ProjectType.Copilot;
839
+ this.options = options;
840
+ this.spec = spec;
841
+ }
842
+ validateSpec() {
843
+ const result = { errors: [], warnings: [] };
844
+ // validate spec version
845
+ let validationResult = this.validateSpecVersion();
846
+ result.errors.push(...validationResult.errors);
847
+ // validate spec server
848
+ validationResult = this.validateSpecServer();
849
+ result.errors.push(...validationResult.errors);
850
+ // validate no supported API
851
+ validationResult = this.validateSpecNoSupportAPI();
852
+ result.errors.push(...validationResult.errors);
853
+ // validate operationId missing
854
+ validationResult = this.validateSpecOperationId();
855
+ result.warnings.push(...validationResult.warnings);
856
+ return result;
857
+ }
858
+ validateAPI(method, path) {
859
+ const result = { isValid: true, reason: [] };
860
+ method = method.toLocaleLowerCase();
861
+ // validate method and path
862
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
863
+ if (!methodAndPathResult.isValid) {
864
+ return methodAndPathResult;
865
+ }
866
+ const operationObject = this.spec.paths[path][method];
867
+ // validate auth
868
+ const authCheckResult = this.validateAuth(method, path);
869
+ result.reason.push(...authCheckResult.reason);
870
+ // validate operationId
871
+ if (!this.options.allowMissingId && !operationObject.operationId) {
872
+ result.reason.push(ErrorType.MissingOperationId);
873
+ }
874
+ // validate server
875
+ const validateServerResult = this.validateServer(method, path);
876
+ result.reason.push(...validateServerResult.reason);
877
+ // validate response
878
+ const validateResponseResult = this.validateResponse(method, path);
879
+ result.reason.push(...validateResponseResult.reason);
880
+ // validate requestBody
881
+ const requestBody = operationObject.requestBody;
882
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
883
+ if (requestJsonBody) {
884
+ const requestBodySchema = requestJsonBody.schema;
885
+ if (requestBodySchema.type !== "object") {
886
+ result.reason.push(ErrorType.PostBodySchemaIsNotJson);
887
+ }
888
+ const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
889
+ result.reason.push(...requestBodyParamResult.reason);
890
+ }
891
+ // validate parameters
892
+ const paramObject = operationObject.parameters;
893
+ const paramResult = this.checkParamSchema(paramObject);
894
+ result.reason.push(...paramResult.reason);
895
+ if (result.reason.length > 0) {
896
+ result.isValid = false;
897
+ }
898
+ return result;
899
+ }
900
+ }
901
+
902
+ // Copyright (c) Microsoft Corporation.
903
+ class SMEValidator extends Validator {
904
+ constructor(spec, options) {
905
+ super();
906
+ this.projectType = ProjectType.SME;
907
+ this.options = options;
908
+ this.spec = spec;
909
+ }
910
+ validateSpec() {
911
+ const result = { errors: [], warnings: [] };
912
+ // validate spec version
913
+ let validationResult = this.validateSpecVersion();
914
+ result.errors.push(...validationResult.errors);
915
+ // validate spec server
916
+ validationResult = this.validateSpecServer();
917
+ result.errors.push(...validationResult.errors);
918
+ // validate no supported API
919
+ validationResult = this.validateSpecNoSupportAPI();
920
+ result.errors.push(...validationResult.errors);
921
+ // validate operationId missing
922
+ if (this.options.allowMissingId) {
923
+ validationResult = this.validateSpecOperationId();
924
+ result.warnings.push(...validationResult.warnings);
925
+ }
926
+ return result;
927
+ }
928
+ validateAPI(method, path) {
929
+ const result = { isValid: true, reason: [] };
930
+ method = method.toLocaleLowerCase();
931
+ // validate method and path
932
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
933
+ if (!methodAndPathResult.isValid) {
934
+ return methodAndPathResult;
935
+ }
936
+ const operationObject = this.spec.paths[path][method];
937
+ // validate auth
938
+ const authCheckResult = this.validateAuth(method, path);
939
+ result.reason.push(...authCheckResult.reason);
940
+ // validate operationId
941
+ if (!this.options.allowMissingId && !operationObject.operationId) {
942
+ result.reason.push(ErrorType.MissingOperationId);
943
+ }
944
+ // validate server
945
+ const validateServerResult = this.validateServer(method, path);
946
+ result.reason.push(...validateServerResult.reason);
947
+ // validate response
948
+ const validateResponseResult = this.validateResponse(method, path);
949
+ result.reason.push(...validateResponseResult.reason);
950
+ let postBodyResult = {
951
+ requiredNum: 0,
952
+ optionalNum: 0,
953
+ isValid: true,
954
+ reason: [],
955
+ };
956
+ // validate requestBody
957
+ const requestBody = operationObject.requestBody;
958
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
959
+ if (Utils.containMultipleMediaTypes(requestBody)) {
960
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
961
+ }
962
+ if (requestJsonBody) {
963
+ const requestBodySchema = requestJsonBody.schema;
964
+ postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
965
+ result.reason.push(...postBodyResult.reason);
966
+ }
967
+ // validate parameters
968
+ const paramObject = operationObject.parameters;
969
+ const paramResult = this.checkParamSchema(paramObject);
970
+ result.reason.push(...paramResult.reason);
971
+ // validate total parameters count
972
+ if (paramResult.isValid && postBodyResult.isValid) {
973
+ const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
974
+ result.reason.push(...paramCountResult.reason);
975
+ }
976
+ if (result.reason.length > 0) {
977
+ result.isValid = false;
978
+ }
979
+ return result;
980
+ }
981
+ validateParamCount(postBodyResult, paramResult) {
982
+ const result = { isValid: true, reason: [] };
983
+ const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
984
+ const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
985
+ if (totalRequiredParams > 1) {
986
+ if (!this.options.allowMultipleParameters ||
987
+ totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
988
+ result.reason.push(ErrorType.ExceededRequiredParamsLimit);
989
+ }
990
+ }
991
+ else if (totalParams === 0) {
992
+ result.reason.push(ErrorType.NoParameter);
993
+ }
994
+ return result;
995
+ }
996
+ }
997
+ SMEValidator.SMERequiredParamsMaxNum = 5;
998
+
999
+ // Copyright (c) Microsoft Corporation.
1000
+ class TeamsAIValidator extends Validator {
1001
+ constructor(spec, options) {
1002
+ super();
1003
+ this.projectType = ProjectType.TeamsAi;
1004
+ this.options = options;
1005
+ this.spec = spec;
1006
+ }
1007
+ validateSpec() {
1008
+ const result = { errors: [], warnings: [] };
1009
+ // validate spec server
1010
+ let validationResult = this.validateSpecServer();
1011
+ result.errors.push(...validationResult.errors);
1012
+ // validate no supported API
1013
+ validationResult = this.validateSpecNoSupportAPI();
1014
+ result.errors.push(...validationResult.errors);
1015
+ return result;
1016
+ }
1017
+ validateAPI(method, path) {
1018
+ const result = { isValid: true, reason: [] };
1019
+ method = method.toLocaleLowerCase();
1020
+ // validate method and path
1021
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
1022
+ if (!methodAndPathResult.isValid) {
1023
+ return methodAndPathResult;
1024
+ }
1025
+ const operationObject = this.spec.paths[path][method];
1026
+ // validate operationId
1027
+ if (!this.options.allowMissingId && !operationObject.operationId) {
1028
+ result.reason.push(ErrorType.MissingOperationId);
1029
+ }
1030
+ // validate server
1031
+ const validateServerResult = this.validateServer(method, path);
1032
+ result.reason.push(...validateServerResult.reason);
1033
+ if (result.reason.length > 0) {
1034
+ result.isValid = false;
1035
+ }
1036
+ return result;
1037
+ }
1038
+ }
1039
+
1040
+ class ValidatorFactory {
1041
+ static create(spec, options) {
1042
+ var _a;
1043
+ const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : ProjectType.SME;
1044
+ switch (type) {
1045
+ case ProjectType.SME:
1046
+ return new SMEValidator(spec, options);
1047
+ case ProjectType.Copilot:
1048
+ return new CopilotValidator(spec, options);
1049
+ case ProjectType.TeamsAi:
1050
+ return new TeamsAIValidator(spec, options);
1051
+ default:
1052
+ throw new Error(`Invalid project type: ${type}`);
797
1053
  }
798
- return safeRegistrationIdEnvName;
799
1054
  }
800
1055
  }
801
1056
 
@@ -818,6 +1073,9 @@ class SpecParser {
818
1073
  allowBearerTokenAuth: false,
819
1074
  allowOauth2: false,
820
1075
  allowMethods: ["get", "post"],
1076
+ allowConversationStarters: false,
1077
+ allowResponseSemantics: false,
1078
+ allowConfirmation: false,
821
1079
  projectType: ProjectType.SME,
822
1080
  };
823
1081
  this.pathOrSpec = pathOrDoc;
@@ -834,11 +1092,7 @@ class SpecParser {
834
1092
  try {
835
1093
  try {
836
1094
  yield this.loadSpec();
837
- yield this.parser.validate(this.spec, {
838
- validate: {
839
- schema: false,
840
- },
841
- });
1095
+ yield this.parser.validate(this.spec);
842
1096
  }
843
1097
  catch (e) {
844
1098
  return {
@@ -847,16 +1101,46 @@ class SpecParser {
847
1101
  errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
848
1102
  };
849
1103
  }
1104
+ const errors = [];
1105
+ const warnings = [];
850
1106
  if (!this.options.allowSwagger && this.isSwaggerFile) {
851
1107
  return {
852
1108
  status: ValidationStatus.Error,
853
1109
  warnings: [],
854
1110
  errors: [
855
- { type: ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1111
+ {
1112
+ type: ErrorType.SwaggerNotSupported,
1113
+ content: ConstantString.SwaggerNotSupported,
1114
+ },
856
1115
  ],
857
1116
  };
858
1117
  }
859
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1118
+ // Remote reference not supported
1119
+ const refPaths = this.parser.$refs.paths();
1120
+ // refPaths [0] is the current spec file path
1121
+ if (refPaths.length > 1) {
1122
+ errors.push({
1123
+ type: ErrorType.RemoteRefNotSupported,
1124
+ content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
1125
+ data: refPaths,
1126
+ });
1127
+ }
1128
+ const validator = this.getValidator(this.spec);
1129
+ const validationResult = validator.validateSpec();
1130
+ warnings.push(...validationResult.warnings);
1131
+ errors.push(...validationResult.errors);
1132
+ let status = ValidationStatus.Valid;
1133
+ if (warnings.length > 0 && errors.length === 0) {
1134
+ status = ValidationStatus.Warning;
1135
+ }
1136
+ else if (errors.length > 0) {
1137
+ status = ValidationStatus.Error;
1138
+ }
1139
+ return {
1140
+ status: status,
1141
+ warnings: warnings,
1142
+ errors: errors,
1143
+ };
860
1144
  }
861
1145
  catch (err) {
862
1146
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -867,17 +1151,20 @@ class SpecParser {
867
1151
  return __awaiter(this, void 0, void 0, function* () {
868
1152
  try {
869
1153
  yield this.loadSpec();
870
- const apiMap = this.getAllSupportedAPIs(this.spec);
1154
+ const apiMap = this.getAPIs(this.spec);
871
1155
  const apiInfos = [];
872
1156
  for (const key in apiMap) {
873
- const pathObjectItem = apiMap[key];
1157
+ const { operation, isValid } = apiMap[key];
1158
+ if (!isValid) {
1159
+ continue;
1160
+ }
874
1161
  const [method, path] = key.split(" ");
875
- const operationId = pathObjectItem.operationId;
1162
+ const operationId = operation.operationId;
876
1163
  // In Browser environment, this api is by default not support api without operationId
877
1164
  if (!operationId) {
878
1165
  continue;
879
1166
  }
880
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
1167
+ const command = Utils.parseApiInfo(operation, this.options);
881
1168
  const apiInfo = {
882
1169
  method: method,
883
1170
  path: path,
@@ -886,9 +1173,6 @@ class SpecParser {
886
1173
  parameters: command.parameters,
887
1174
  description: command.description,
888
1175
  };
889
- if (warning) {
890
- apiInfo.warning = warning;
891
- }
892
1176
  apiInfos.push(apiInfo);
893
1177
  }
894
1178
  return apiInfos;
@@ -958,13 +1242,18 @@ class SpecParser {
958
1242
  }
959
1243
  });
960
1244
  }
961
- getAllSupportedAPIs(spec) {
962
- if (this.apiMap !== undefined) {
963
- return this.apiMap;
1245
+ getAPIs(spec) {
1246
+ const validator = this.getValidator(spec);
1247
+ const apiMap = validator.listAPIs();
1248
+ return apiMap;
1249
+ }
1250
+ getValidator(spec) {
1251
+ if (this.validator) {
1252
+ return this.validator;
964
1253
  }
965
- const result = Utils.listSupportedAPIs(spec, this.options);
966
- this.apiMap = result;
967
- return result;
1254
+ const validator = ValidatorFactory.create(spec, this.options);
1255
+ this.validator = validator;
1256
+ return validator;
968
1257
  }
969
1258
  }
970
1259
 
@@ -972,7 +1261,7 @@ class SpecParser {
972
1261
  class AdaptiveCardGenerator {
973
1262
  static generateAdaptiveCard(operationItem) {
974
1263
  try {
975
- const json = Utils.getResponseJson(operationItem);
1264
+ const { json } = Utils.getResponseJson(operationItem);
976
1265
  let cardBody = [];
977
1266
  let schema = json.schema;
978
1267
  let jsonPath = "$";