@microsoft/m365-spec-parser 0.1.1-alpha.e17ffd4d1.0 → 0.1.1-alpha.e1b11d5b2.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 = {}));
@@ -101,7 +117,7 @@ ConstantString.RemoteRefNotSupported = "Remote reference is not supported: %s.";
101
117
  ConstantString.MissingOperationId = "Missing operationIds: %s.";
102
118
  ConstantString.NoSupportedApi = "No supported API is found in the OpenAPI description document: only GET and POST methods are supported, additionally, there can be at most one required parameter, and no auth is allowed.";
103
119
  ConstantString.AdditionalPropertiesNotSupported = "'additionalProperties' is not supported, and will be ignored.";
104
- ConstantString.SchemaNotSupported = "'oneOf', 'anyOf', and 'not' schema are not supported: %s.";
120
+ ConstantString.SchemaNotSupported = "'oneOf', 'allOf', 'anyOf', and 'not' schema are not supported: %s.";
105
121
  ConstantString.UnknownSchema = "Unknown schema: %s.";
106
122
  ConstantString.UrlProtocolNotSupported = "Server url is not correct: protocol %s is not supported, you should use https protocol instead.";
107
123
  ConstantString.RelativeServerUrlNotSupported = "Server url is not correct: relative server url is not supported.";
@@ -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,9 +137,14 @@ 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
- ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
125
- ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
142
+ ConstantString.RegistrationIdPostfix = {
143
+ apiKey: "REGISTRATION_ID",
144
+ oauth2: "CONFIGURATION_ID",
145
+ http: "REGISTRATION_ID",
146
+ openIdConnect: "REGISTRATION_ID",
147
+ };
126
148
  ConstantString.ResponseCodeFor20X = [
127
149
  "200",
128
150
  "201",
@@ -181,9 +203,11 @@ ConstantString.ShortDescriptionMaxLens = 80;
181
203
  ConstantString.FullDescriptionMaxLens = 4000;
182
204
  ConstantString.CommandDescriptionMaxLens = 128;
183
205
  ConstantString.ParameterDescriptionMaxLens = 128;
206
+ ConstantString.ConversationStarterMaxLens = 50;
184
207
  ConstantString.CommandTitleMaxLens = 32;
185
208
  ConstantString.ParameterTitleMaxLens = 32;
186
- ConstantString.SMERequiredParamsMaxNum = 5;
209
+ ConstantString.SMERequiredParamsMaxNum = 5;
210
+ ConstantString.DefaultPluginId = "plugin_1";
187
211
 
188
212
  // Copyright (c) Microsoft Corporation.
189
213
  class Utils {
@@ -198,253 +222,33 @@ class Utils {
198
222
  }
199
223
  return false;
200
224
  }
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
225
  static containMultipleMediaTypes(bodyObject) {
300
226
  return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
301
227
  }
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(authSchemaArray, options) {
396
- if (authSchemaArray.length === 0) {
397
- return true;
398
- }
399
- if (options.allowAPIKeyAuth || options.allowOauth2) {
400
- // Currently we don't support multiple auth in one operation
401
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
402
- return false;
403
- }
404
- for (const auths of authSchemaArray) {
405
- if (auths.length === 1) {
406
- if (!options.allowOauth2 &&
407
- options.allowAPIKeyAuth &&
408
- Utils.isAPIKeyAuth(auths[0].authSchema)) {
409
- return true;
410
- }
411
- else if (!options.allowAPIKeyAuth &&
412
- options.allowOauth2 &&
413
- Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema)) {
414
- return true;
415
- }
416
- else if (options.allowAPIKeyAuth &&
417
- options.allowOauth2 &&
418
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
419
- Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema))) {
420
- return true;
421
- }
422
- }
423
- }
424
- }
425
- return false;
228
+ static isBearerTokenAuth(authScheme) {
229
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
426
230
  }
427
- static isAPIKeyAuth(authSchema) {
428
- return authSchema.type === "apiKey";
231
+ static isAPIKeyAuth(authScheme) {
232
+ return authScheme.type === "apiKey";
429
233
  }
430
- static isOAuthWithAuthCodeFlow(authSchema) {
431
- if (authSchema.type === "oauth2" && authSchema.flows && authSchema.flows.authorizationCode) {
432
- return true;
433
- }
434
- return false;
234
+ static isOAuthWithAuthCodeFlow(authScheme) {
235
+ return !!(authScheme.type === "oauth2" &&
236
+ authScheme.flows &&
237
+ authScheme.flows.authorizationCode);
435
238
  }
436
239
  static getAuthArray(securities, spec) {
437
240
  var _a;
438
241
  const result = [];
439
242
  const securitySchemas = (_a = spec.components) === null || _a === void 0 ? void 0 : _a.securitySchemes;
440
- if (securities && securitySchemas) {
441
- for (let i = 0; i < securities.length; i++) {
442
- const security = securities[i];
243
+ const securitiesArr = securities !== null && securities !== void 0 ? securities : spec.security;
244
+ if (securitiesArr && securitySchemas) {
245
+ for (let i = 0; i < securitiesArr.length; i++) {
246
+ const security = securitiesArr[i];
443
247
  const authArray = [];
444
248
  for (const name in security) {
445
249
  const auth = securitySchemas[name];
446
250
  authArray.push({
447
- authSchema: auth,
251
+ authScheme: auth,
448
252
  name: name,
449
253
  });
450
254
  }
@@ -456,17 +260,39 @@ class Utils {
456
260
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
457
261
  return result;
458
262
  }
263
+ static getAuthInfo(spec) {
264
+ let authInfo = undefined;
265
+ for (const url in spec.paths) {
266
+ for (const method in spec.paths[url]) {
267
+ const operation = spec.paths[url][method];
268
+ const authArray = Utils.getAuthArray(operation.security, spec);
269
+ if (authArray && authArray.length > 0) {
270
+ const currentAuth = authArray[0][0];
271
+ if (!authInfo) {
272
+ authInfo = authArray[0][0];
273
+ }
274
+ else if (authInfo.name !== currentAuth.name) {
275
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
276
+ }
277
+ }
278
+ }
279
+ }
280
+ return authInfo;
281
+ }
459
282
  static updateFirstLetter(str) {
460
283
  return str.charAt(0).toUpperCase() + str.slice(1);
461
284
  }
462
- static getResponseJson(operationObject, isTeamsAiProject = false) {
285
+ static getResponseJson(operationObject) {
463
286
  var _a, _b;
464
287
  let json = {};
288
+ let multipleMediaType = false;
465
289
  for (const code of ConstantString.ResponseCodeFor20X) {
466
290
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
467
291
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
292
+ multipleMediaType = false;
468
293
  json = responseObject.content["application/json"];
469
- if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
294
+ if (Utils.containMultipleMediaTypes(responseObject)) {
295
+ multipleMediaType = true;
470
296
  json = {};
471
297
  }
472
298
  else {
@@ -474,7 +300,7 @@ class Utils {
474
300
  }
475
301
  }
476
302
  }
477
- return json;
303
+ return { json, multipleMediaType };
478
304
  }
479
305
  static convertPathToCamelCase(path) {
480
306
  const pathSegments = path.split(/[./{]/);
@@ -494,10 +320,10 @@ class Utils {
494
320
  return undefined;
495
321
  }
496
322
  }
497
- static resolveServerUrl(url) {
323
+ static resolveEnv(str) {
498
324
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
499
- let matches = placeHolderReg.exec(url);
500
- let newUrl = url;
325
+ let matches = placeHolderReg.exec(str);
326
+ let newStr = str;
501
327
  while (matches != null) {
502
328
  const envVar = matches[1];
503
329
  const envVal = process.env[envVar];
@@ -505,17 +331,17 @@ class Utils {
505
331
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
506
332
  }
507
333
  else {
508
- newUrl = newUrl.replace(matches[0], envVal);
334
+ newStr = newStr.replace(matches[0], envVal);
509
335
  }
510
- matches = placeHolderReg.exec(url);
336
+ matches = placeHolderReg.exec(str);
511
337
  }
512
- return newUrl;
338
+ return newStr;
513
339
  }
514
340
  static checkServerUrl(servers) {
515
341
  const errors = [];
516
342
  let serverUrl;
517
343
  try {
518
- serverUrl = Utils.resolveServerUrl(servers[0].url);
344
+ serverUrl = Utils.resolveEnv(servers[0].url);
519
345
  }
520
346
  catch (err) {
521
347
  errors.push({
@@ -546,6 +372,7 @@ class Utils {
546
372
  return errors;
547
373
  }
548
374
  static validateServer(spec, options) {
375
+ var _a;
549
376
  const errors = [];
550
377
  let hasTopLevelServers = false;
551
378
  let hasPathLevelServers = false;
@@ -566,7 +393,7 @@ class Utils {
566
393
  }
567
394
  for (const method in methods) {
568
395
  const operationObject = methods[method];
569
- if (Utils.isSupportedApi(method, path, spec, options)) {
396
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
570
397
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
571
398
  hasOperationLevelServers = true;
572
399
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -609,6 +436,7 @@ class Utils {
609
436
  Utils.updateParameterWithInputType(schema, parameter);
610
437
  }
611
438
  if (isRequired && schema.default === undefined) {
439
+ parameter.isRequired = true;
612
440
  requiredParams.push(parameter);
613
441
  }
614
442
  else {
@@ -672,6 +500,7 @@ class Utils {
672
500
  }
673
501
  if (param.in !== "header" && param.in !== "cookie") {
674
502
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
503
+ parameter.isRequired = true;
675
504
  requiredParams.push(parameter);
676
505
  }
677
506
  else {
@@ -691,13 +520,7 @@ class Utils {
691
520
  }
692
521
  }
693
522
  const operationId = operationItem.operationId;
694
- const parameters = [];
695
- if (requiredParams.length !== 0) {
696
- parameters.push(...requiredParams);
697
- }
698
- else {
699
- parameters.push(optionalParams[0]);
700
- }
523
+ const parameters = [...requiredParams, ...optionalParams];
701
524
  const command = {
702
525
  context: ["compose"],
703
526
  type: "query",
@@ -706,104 +529,534 @@ class Utils {
706
529
  parameters: parameters,
707
530
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
708
531
  };
709
- let warning = undefined;
710
- if (requiredParams.length === 0 && optionalParams.length > 1) {
711
- warning = {
712
- type: WarningType.OperationOnlyContainsOptionalParam,
713
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
714
- data: operationId,
715
- };
532
+ return command;
533
+ }
534
+ static format(str, ...args) {
535
+ let index = 0;
536
+ return str.replace(/%s/g, () => {
537
+ const arg = args[index++];
538
+ return arg !== undefined ? arg : "";
539
+ });
540
+ }
541
+ static getSafeRegistrationIdEnvName(authName) {
542
+ if (!authName) {
543
+ return "";
716
544
  }
717
- return [command, warning];
545
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
546
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
547
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
548
+ }
549
+ return safeRegistrationIdEnvName;
718
550
  }
719
- static listSupportedAPIs(spec, options) {
720
- const paths = spec.paths;
551
+ static getServerObject(spec, method, path) {
552
+ const pathObj = spec.paths[path];
553
+ const operationObject = pathObj[method];
554
+ const rootServer = spec.servers && spec.servers[0];
555
+ const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
556
+ const operationServer = operationObject.servers && operationObject.servers[0];
557
+ const serverUrl = operationServer || methodServer || rootServer;
558
+ return serverUrl;
559
+ }
560
+ }
561
+
562
+ // Copyright (c) Microsoft Corporation.
563
+ class Validator {
564
+ listAPIs() {
565
+ var _a;
566
+ if (this.apiMap) {
567
+ return this.apiMap;
568
+ }
569
+ const paths = this.spec.paths;
721
570
  const result = {};
722
571
  for (const path in paths) {
723
572
  const methods = paths[path];
724
573
  for (const method in methods) {
725
- if (Utils.isSupportedApi(method, path, spec, options)) {
726
- const operationObject = methods[method];
727
- result[`${method.toUpperCase()} ${path}`] = operationObject;
574
+ const operationObject = methods[method];
575
+ if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
576
+ const validateResult = this.validateAPI(method, path);
577
+ result[`${method.toUpperCase()} ${path}`] = {
578
+ operation: operationObject,
579
+ isValid: validateResult.isValid,
580
+ reason: validateResult.reason,
581
+ };
728
582
  }
729
583
  }
730
584
  }
585
+ this.apiMap = result;
731
586
  return result;
732
587
  }
733
- static validateSpec(spec, parser, isSwaggerFile, options) {
734
- const errors = [];
735
- const warnings = [];
736
- if (isSwaggerFile) {
737
- warnings.push({
738
- type: WarningType.ConvertSwaggerToOpenAPI,
739
- content: ConstantString.ConvertSwaggerToOpenAPI,
740
- });
741
- }
742
- // Server validation
743
- const serverErrors = Utils.validateServer(spec, options);
744
- errors.push(...serverErrors);
745
- // Remote reference not supported
746
- const refPaths = parser.$refs.paths();
747
- // refPaths [0] is the current spec file path
748
- if (refPaths.length > 1) {
749
- errors.push({
750
- type: ErrorType.RemoteRefNotSupported,
751
- content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
752
- data: refPaths,
588
+ validateSpecVersion() {
589
+ const result = { errors: [], warnings: [] };
590
+ if (this.spec.openapi >= "3.1.0") {
591
+ result.errors.push({
592
+ type: ErrorType.SpecVersionNotSupported,
593
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
594
+ data: this.spec.openapi,
753
595
  });
754
596
  }
755
- // No supported API
756
- const apiMap = Utils.listSupportedAPIs(spec, options);
757
- if (Object.keys(apiMap).length === 0) {
758
- errors.push({
597
+ return result;
598
+ }
599
+ validateSpecServer() {
600
+ const result = { errors: [], warnings: [] };
601
+ const serverErrors = Utils.validateServer(this.spec, this.options);
602
+ result.errors.push(...serverErrors);
603
+ return result;
604
+ }
605
+ validateSpecNoSupportAPI() {
606
+ const result = { errors: [], warnings: [] };
607
+ const apiMap = this.listAPIs();
608
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
609
+ if (validAPIs.length === 0) {
610
+ const data = [];
611
+ for (const key in apiMap) {
612
+ const { reason } = apiMap[key];
613
+ const apiInvalidReason = { api: key, reason: reason };
614
+ data.push(apiInvalidReason);
615
+ }
616
+ result.errors.push({
759
617
  type: ErrorType.NoSupportedApi,
760
618
  content: ConstantString.NoSupportedApi,
619
+ data,
761
620
  });
762
621
  }
622
+ return result;
623
+ }
624
+ validateSpecOperationId() {
625
+ const result = { errors: [], warnings: [] };
626
+ const apiMap = this.listAPIs();
763
627
  // OperationId missing
764
628
  const apisMissingOperationId = [];
765
629
  for (const key in apiMap) {
766
- const pathObjectItem = apiMap[key];
767
- if (!pathObjectItem.operationId) {
630
+ const { operation } = apiMap[key];
631
+ if (!operation.operationId) {
768
632
  apisMissingOperationId.push(key);
769
633
  }
770
634
  }
771
635
  if (apisMissingOperationId.length > 0) {
772
- warnings.push({
636
+ result.warnings.push({
773
637
  type: WarningType.OperationIdMissing,
774
638
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
775
639
  data: apisMissingOperationId,
776
640
  });
777
641
  }
778
- let status = ValidationStatus.Valid;
779
- if (warnings.length > 0 && errors.length === 0) {
780
- status = ValidationStatus.Warning;
642
+ return result;
643
+ }
644
+ validateMethodAndPath(method, path) {
645
+ const result = { isValid: true, reason: [] };
646
+ if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
647
+ result.isValid = false;
648
+ result.reason.push(ErrorType.MethodNotAllowed);
649
+ return result;
650
+ }
651
+ const pathObj = this.spec.paths[path];
652
+ if (!pathObj || !pathObj[method]) {
653
+ result.isValid = false;
654
+ result.reason.push(ErrorType.UrlPathNotExist);
655
+ return result;
656
+ }
657
+ return result;
658
+ }
659
+ validateResponse(method, path) {
660
+ const result = { isValid: true, reason: [] };
661
+ const operationObject = this.spec.paths[path][method];
662
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
663
+ if (this.options.projectType === ProjectType.SME) {
664
+ // only support response body only contains “application/json” content type
665
+ if (multipleMediaType) {
666
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
667
+ }
668
+ else if (Object.keys(json).length === 0) {
669
+ // response body should not be empty
670
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
671
+ }
672
+ }
673
+ return result;
674
+ }
675
+ validateServer(method, path) {
676
+ const result = { isValid: true, reason: [] };
677
+ const serverObj = Utils.getServerObject(this.spec, method, path);
678
+ if (!serverObj) {
679
+ // should contain server URL
680
+ result.reason.push(ErrorType.NoServerInformation);
781
681
  }
782
- else if (errors.length > 0) {
783
- status = ValidationStatus.Error;
682
+ else {
683
+ // server url should be absolute url with https protocol
684
+ const serverValidateResult = Utils.checkServerUrl([serverObj]);
685
+ result.reason.push(...serverValidateResult.map((item) => item.type));
686
+ }
687
+ return result;
688
+ }
689
+ validateAuth(method, path) {
690
+ const pathObj = this.spec.paths[path];
691
+ const operationObject = pathObj[method];
692
+ const securities = operationObject.security;
693
+ const authSchemeArray = Utils.getAuthArray(securities, this.spec);
694
+ if (authSchemeArray.length === 0) {
695
+ return { isValid: true, reason: [] };
784
696
  }
785
- return {
786
- status,
787
- warnings,
788
- errors,
697
+ if (this.options.allowAPIKeyAuth ||
698
+ this.options.allowOauth2 ||
699
+ this.options.allowBearerTokenAuth) {
700
+ // Currently we don't support multiple auth in one operation
701
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
702
+ return {
703
+ isValid: false,
704
+ reason: [ErrorType.MultipleAuthNotSupported],
705
+ };
706
+ }
707
+ for (const auths of authSchemeArray) {
708
+ if (auths.length === 1) {
709
+ if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
710
+ (this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
711
+ (this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
712
+ return { isValid: true, reason: [] };
713
+ }
714
+ }
715
+ }
716
+ }
717
+ return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
718
+ }
719
+ checkPostBodySchema(schema, isRequired = false) {
720
+ var _a;
721
+ const paramResult = {
722
+ requiredNum: 0,
723
+ optionalNum: 0,
724
+ isValid: true,
725
+ reason: [],
789
726
  };
727
+ if (Object.keys(schema).length === 0) {
728
+ return paramResult;
729
+ }
730
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
731
+ const isCopilot = this.projectType === ProjectType.Copilot;
732
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
733
+ paramResult.isValid = false;
734
+ paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
735
+ return paramResult;
736
+ }
737
+ if (schema.type === "string" ||
738
+ schema.type === "integer" ||
739
+ schema.type === "boolean" ||
740
+ schema.type === "number") {
741
+ if (isRequiredWithoutDefault) {
742
+ paramResult.requiredNum = paramResult.requiredNum + 1;
743
+ }
744
+ else {
745
+ paramResult.optionalNum = paramResult.optionalNum + 1;
746
+ }
747
+ }
748
+ else if (schema.type === "object") {
749
+ const { properties } = schema;
750
+ for (const property in properties) {
751
+ let isRequired = false;
752
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
753
+ isRequired = true;
754
+ }
755
+ const result = this.checkPostBodySchema(properties[property], isRequired);
756
+ paramResult.requiredNum += result.requiredNum;
757
+ paramResult.optionalNum += result.optionalNum;
758
+ paramResult.isValid = paramResult.isValid && result.isValid;
759
+ paramResult.reason.push(...result.reason);
760
+ }
761
+ }
762
+ else {
763
+ if (isRequiredWithoutDefault && !isCopilot) {
764
+ paramResult.isValid = false;
765
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
766
+ }
767
+ }
768
+ return paramResult;
790
769
  }
791
- static format(str, ...args) {
792
- let index = 0;
793
- return str.replace(/%s/g, () => {
794
- const arg = args[index++];
795
- return arg !== undefined ? arg : "";
796
- });
770
+ checkParamSchema(paramObject) {
771
+ const paramResult = {
772
+ requiredNum: 0,
773
+ optionalNum: 0,
774
+ isValid: true,
775
+ reason: [],
776
+ };
777
+ if (!paramObject) {
778
+ return paramResult;
779
+ }
780
+ const isCopilot = this.projectType === ProjectType.Copilot;
781
+ for (let i = 0; i < paramObject.length; i++) {
782
+ const param = paramObject[i];
783
+ const schema = param.schema;
784
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
785
+ paramResult.isValid = false;
786
+ paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
787
+ continue;
788
+ }
789
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
790
+ if (isCopilot) {
791
+ if (isRequiredWithoutDefault) {
792
+ paramResult.requiredNum = paramResult.requiredNum + 1;
793
+ }
794
+ else {
795
+ paramResult.optionalNum = paramResult.optionalNum + 1;
796
+ }
797
+ continue;
798
+ }
799
+ if (param.in === "header" || param.in === "cookie") {
800
+ if (isRequiredWithoutDefault) {
801
+ paramResult.isValid = false;
802
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
803
+ }
804
+ continue;
805
+ }
806
+ if (schema.type !== "boolean" &&
807
+ schema.type !== "string" &&
808
+ schema.type !== "number" &&
809
+ schema.type !== "integer") {
810
+ if (isRequiredWithoutDefault) {
811
+ paramResult.isValid = false;
812
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
813
+ }
814
+ continue;
815
+ }
816
+ if (param.in === "query" || param.in === "path") {
817
+ if (isRequiredWithoutDefault) {
818
+ paramResult.requiredNum = paramResult.requiredNum + 1;
819
+ }
820
+ else {
821
+ paramResult.optionalNum = paramResult.optionalNum + 1;
822
+ }
823
+ }
824
+ }
825
+ return paramResult;
797
826
  }
798
- static getSafeRegistrationIdEnvName(authName) {
799
- if (!authName) {
800
- return "";
827
+ hasNestedObjectInSchema(schema) {
828
+ if (schema.type === "object") {
829
+ for (const property in schema.properties) {
830
+ const nestedSchema = schema.properties[property];
831
+ if (nestedSchema.type === "object") {
832
+ return true;
833
+ }
834
+ }
801
835
  }
802
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
803
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
804
- safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
836
+ return false;
837
+ }
838
+ }
839
+
840
+ // Copyright (c) Microsoft Corporation.
841
+ class CopilotValidator extends Validator {
842
+ constructor(spec, options) {
843
+ super();
844
+ this.projectType = ProjectType.Copilot;
845
+ this.options = options;
846
+ this.spec = spec;
847
+ }
848
+ validateSpec() {
849
+ const result = { errors: [], warnings: [] };
850
+ // validate spec version
851
+ let validationResult = this.validateSpecVersion();
852
+ result.errors.push(...validationResult.errors);
853
+ // validate spec server
854
+ validationResult = this.validateSpecServer();
855
+ result.errors.push(...validationResult.errors);
856
+ // validate no supported API
857
+ validationResult = this.validateSpecNoSupportAPI();
858
+ result.errors.push(...validationResult.errors);
859
+ // validate operationId missing
860
+ validationResult = this.validateSpecOperationId();
861
+ result.warnings.push(...validationResult.warnings);
862
+ return result;
863
+ }
864
+ validateAPI(method, path) {
865
+ const result = { isValid: true, reason: [] };
866
+ method = method.toLocaleLowerCase();
867
+ // validate method and path
868
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
869
+ if (!methodAndPathResult.isValid) {
870
+ return methodAndPathResult;
871
+ }
872
+ const operationObject = this.spec.paths[path][method];
873
+ // validate auth
874
+ const authCheckResult = this.validateAuth(method, path);
875
+ result.reason.push(...authCheckResult.reason);
876
+ // validate operationId
877
+ if (!this.options.allowMissingId && !operationObject.operationId) {
878
+ result.reason.push(ErrorType.MissingOperationId);
879
+ }
880
+ // validate server
881
+ const validateServerResult = this.validateServer(method, path);
882
+ result.reason.push(...validateServerResult.reason);
883
+ // validate response
884
+ const validateResponseResult = this.validateResponse(method, path);
885
+ result.reason.push(...validateResponseResult.reason);
886
+ // validate requestBody
887
+ const requestBody = operationObject.requestBody;
888
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
889
+ if (requestJsonBody) {
890
+ const requestBodySchema = requestJsonBody.schema;
891
+ if (requestBodySchema.type !== "object") {
892
+ result.reason.push(ErrorType.PostBodySchemaIsNotJson);
893
+ }
894
+ const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
895
+ result.reason.push(...requestBodyParamResult.reason);
896
+ }
897
+ // validate parameters
898
+ const paramObject = operationObject.parameters;
899
+ const paramResult = this.checkParamSchema(paramObject);
900
+ result.reason.push(...paramResult.reason);
901
+ if (result.reason.length > 0) {
902
+ result.isValid = false;
903
+ }
904
+ return result;
905
+ }
906
+ }
907
+
908
+ // Copyright (c) Microsoft Corporation.
909
+ class SMEValidator extends Validator {
910
+ constructor(spec, options) {
911
+ super();
912
+ this.projectType = ProjectType.SME;
913
+ this.options = options;
914
+ this.spec = spec;
915
+ }
916
+ validateSpec() {
917
+ const result = { errors: [], warnings: [] };
918
+ // validate spec version
919
+ let validationResult = this.validateSpecVersion();
920
+ result.errors.push(...validationResult.errors);
921
+ // validate spec server
922
+ validationResult = this.validateSpecServer();
923
+ result.errors.push(...validationResult.errors);
924
+ // validate no supported API
925
+ validationResult = this.validateSpecNoSupportAPI();
926
+ result.errors.push(...validationResult.errors);
927
+ // validate operationId missing
928
+ if (this.options.allowMissingId) {
929
+ validationResult = this.validateSpecOperationId();
930
+ result.warnings.push(...validationResult.warnings);
931
+ }
932
+ return result;
933
+ }
934
+ validateAPI(method, path) {
935
+ const result = { isValid: true, reason: [] };
936
+ method = method.toLocaleLowerCase();
937
+ // validate method and path
938
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
939
+ if (!methodAndPathResult.isValid) {
940
+ return methodAndPathResult;
941
+ }
942
+ const operationObject = this.spec.paths[path][method];
943
+ // validate auth
944
+ const authCheckResult = this.validateAuth(method, path);
945
+ result.reason.push(...authCheckResult.reason);
946
+ // validate operationId
947
+ if (!this.options.allowMissingId && !operationObject.operationId) {
948
+ result.reason.push(ErrorType.MissingOperationId);
949
+ }
950
+ // validate server
951
+ const validateServerResult = this.validateServer(method, path);
952
+ result.reason.push(...validateServerResult.reason);
953
+ // validate response
954
+ const validateResponseResult = this.validateResponse(method, path);
955
+ result.reason.push(...validateResponseResult.reason);
956
+ let postBodyResult = {
957
+ requiredNum: 0,
958
+ optionalNum: 0,
959
+ isValid: true,
960
+ reason: [],
961
+ };
962
+ // validate requestBody
963
+ const requestBody = operationObject.requestBody;
964
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
965
+ if (Utils.containMultipleMediaTypes(requestBody)) {
966
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
967
+ }
968
+ if (requestJsonBody) {
969
+ const requestBodySchema = requestJsonBody.schema;
970
+ postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
971
+ result.reason.push(...postBodyResult.reason);
972
+ }
973
+ // validate parameters
974
+ const paramObject = operationObject.parameters;
975
+ const paramResult = this.checkParamSchema(paramObject);
976
+ result.reason.push(...paramResult.reason);
977
+ // validate total parameters count
978
+ if (paramResult.isValid && postBodyResult.isValid) {
979
+ const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
980
+ result.reason.push(...paramCountResult.reason);
981
+ }
982
+ if (result.reason.length > 0) {
983
+ result.isValid = false;
984
+ }
985
+ return result;
986
+ }
987
+ validateParamCount(postBodyResult, paramResult) {
988
+ const result = { isValid: true, reason: [] };
989
+ const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
990
+ const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
991
+ if (totalRequiredParams > 1) {
992
+ if (!this.options.allowMultipleParameters ||
993
+ totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
994
+ result.reason.push(ErrorType.ExceededRequiredParamsLimit);
995
+ }
996
+ }
997
+ else if (totalParams === 0) {
998
+ result.reason.push(ErrorType.NoParameter);
999
+ }
1000
+ return result;
1001
+ }
1002
+ }
1003
+ SMEValidator.SMERequiredParamsMaxNum = 5;
1004
+
1005
+ // Copyright (c) Microsoft Corporation.
1006
+ class TeamsAIValidator extends Validator {
1007
+ constructor(spec, options) {
1008
+ super();
1009
+ this.projectType = ProjectType.TeamsAi;
1010
+ this.options = options;
1011
+ this.spec = spec;
1012
+ }
1013
+ validateSpec() {
1014
+ const result = { errors: [], warnings: [] };
1015
+ // validate spec server
1016
+ let validationResult = this.validateSpecServer();
1017
+ result.errors.push(...validationResult.errors);
1018
+ // validate no supported API
1019
+ validationResult = this.validateSpecNoSupportAPI();
1020
+ result.errors.push(...validationResult.errors);
1021
+ return result;
1022
+ }
1023
+ validateAPI(method, path) {
1024
+ const result = { isValid: true, reason: [] };
1025
+ method = method.toLocaleLowerCase();
1026
+ // validate method and path
1027
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
1028
+ if (!methodAndPathResult.isValid) {
1029
+ return methodAndPathResult;
1030
+ }
1031
+ const operationObject = this.spec.paths[path][method];
1032
+ // validate operationId
1033
+ if (!this.options.allowMissingId && !operationObject.operationId) {
1034
+ result.reason.push(ErrorType.MissingOperationId);
1035
+ }
1036
+ // validate server
1037
+ const validateServerResult = this.validateServer(method, path);
1038
+ result.reason.push(...validateServerResult.reason);
1039
+ if (result.reason.length > 0) {
1040
+ result.isValid = false;
1041
+ }
1042
+ return result;
1043
+ }
1044
+ }
1045
+
1046
+ class ValidatorFactory {
1047
+ static create(spec, options) {
1048
+ var _a;
1049
+ const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : ProjectType.SME;
1050
+ switch (type) {
1051
+ case ProjectType.SME:
1052
+ return new SMEValidator(spec, options);
1053
+ case ProjectType.Copilot:
1054
+ return new CopilotValidator(spec, options);
1055
+ case ProjectType.TeamsAi:
1056
+ return new TeamsAIValidator(spec, options);
1057
+ default:
1058
+ throw new Error(`Invalid project type: ${type}`);
805
1059
  }
806
- return safeRegistrationIdEnvName;
807
1060
  }
808
1061
  }
809
1062
 
@@ -823,9 +1076,14 @@ class SpecParser {
823
1076
  allowSwagger: false,
824
1077
  allowAPIKeyAuth: false,
825
1078
  allowMultipleParameters: false,
1079
+ allowBearerTokenAuth: false,
826
1080
  allowOauth2: false,
827
1081
  allowMethods: ["get", "post"],
1082
+ allowConversationStarters: false,
1083
+ allowResponseSemantics: false,
1084
+ allowConfirmation: false,
828
1085
  projectType: ProjectType.SME,
1086
+ isGptPlugin: false,
829
1087
  };
830
1088
  this.pathOrSpec = pathOrDoc;
831
1089
  this.parser = new SwaggerParser();
@@ -841,11 +1099,7 @@ class SpecParser {
841
1099
  try {
842
1100
  try {
843
1101
  yield this.loadSpec();
844
- yield this.parser.validate(this.spec, {
845
- validate: {
846
- schema: false,
847
- },
848
- });
1102
+ yield this.parser.validate(this.spec);
849
1103
  }
850
1104
  catch (e) {
851
1105
  return {
@@ -854,16 +1108,46 @@ class SpecParser {
854
1108
  errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
855
1109
  };
856
1110
  }
1111
+ const errors = [];
1112
+ const warnings = [];
857
1113
  if (!this.options.allowSwagger && this.isSwaggerFile) {
858
1114
  return {
859
1115
  status: ValidationStatus.Error,
860
1116
  warnings: [],
861
1117
  errors: [
862
- { type: ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1118
+ {
1119
+ type: ErrorType.SwaggerNotSupported,
1120
+ content: ConstantString.SwaggerNotSupported,
1121
+ },
863
1122
  ],
864
1123
  };
865
1124
  }
866
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1125
+ // Remote reference not supported
1126
+ const refPaths = this.parser.$refs.paths();
1127
+ // refPaths [0] is the current spec file path
1128
+ if (refPaths.length > 1) {
1129
+ errors.push({
1130
+ type: ErrorType.RemoteRefNotSupported,
1131
+ content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
1132
+ data: refPaths,
1133
+ });
1134
+ }
1135
+ const validator = this.getValidator(this.spec);
1136
+ const validationResult = validator.validateSpec();
1137
+ warnings.push(...validationResult.warnings);
1138
+ errors.push(...validationResult.errors);
1139
+ let status = ValidationStatus.Valid;
1140
+ if (warnings.length > 0 && errors.length === 0) {
1141
+ status = ValidationStatus.Warning;
1142
+ }
1143
+ else if (errors.length > 0) {
1144
+ status = ValidationStatus.Error;
1145
+ }
1146
+ return {
1147
+ status: status,
1148
+ warnings: warnings,
1149
+ errors: errors,
1150
+ };
867
1151
  }
868
1152
  catch (err) {
869
1153
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -874,17 +1158,20 @@ class SpecParser {
874
1158
  return __awaiter(this, void 0, void 0, function* () {
875
1159
  try {
876
1160
  yield this.loadSpec();
877
- const apiMap = this.getAllSupportedAPIs(this.spec);
1161
+ const apiMap = this.getAPIs(this.spec);
878
1162
  const apiInfos = [];
879
1163
  for (const key in apiMap) {
880
- const pathObjectItem = apiMap[key];
1164
+ const { operation, isValid } = apiMap[key];
1165
+ if (!isValid) {
1166
+ continue;
1167
+ }
881
1168
  const [method, path] = key.split(" ");
882
- const operationId = pathObjectItem.operationId;
1169
+ const operationId = operation.operationId;
883
1170
  // In Browser environment, this api is by default not support api without operationId
884
1171
  if (!operationId) {
885
1172
  continue;
886
1173
  }
887
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
1174
+ const command = Utils.parseApiInfo(operation, this.options);
888
1175
  const apiInfo = {
889
1176
  method: method,
890
1177
  path: path,
@@ -893,9 +1180,6 @@ class SpecParser {
893
1180
  parameters: command.parameters,
894
1181
  description: command.description,
895
1182
  };
896
- if (warning) {
897
- apiInfo.warning = warning;
898
- }
899
1183
  apiInfos.push(apiInfo);
900
1184
  }
901
1185
  return apiInfos;
@@ -965,13 +1249,18 @@ class SpecParser {
965
1249
  }
966
1250
  });
967
1251
  }
968
- getAllSupportedAPIs(spec) {
969
- if (this.apiMap !== undefined) {
970
- return this.apiMap;
1252
+ getAPIs(spec) {
1253
+ const validator = this.getValidator(spec);
1254
+ const apiMap = validator.listAPIs();
1255
+ return apiMap;
1256
+ }
1257
+ getValidator(spec) {
1258
+ if (this.validator) {
1259
+ return this.validator;
971
1260
  }
972
- const result = Utils.listSupportedAPIs(spec, this.options);
973
- this.apiMap = result;
974
- return result;
1261
+ const validator = ValidatorFactory.create(spec, this.options);
1262
+ this.validator = validator;
1263
+ return validator;
975
1264
  }
976
1265
  }
977
1266
 
@@ -979,7 +1268,7 @@ class SpecParser {
979
1268
  class AdaptiveCardGenerator {
980
1269
  static generateAdaptiveCard(operationItem) {
981
1270
  try {
982
- const json = Utils.getResponseJson(operationItem);
1271
+ const { json } = Utils.getResponseJson(operationItem);
983
1272
  let cardBody = [];
984
1273
  let schema = json.schema;
985
1274
  let jsonPath = "$";