@microsoft/m365-spec-parser 0.1.1-alpha.f04ac4ba4.0 → 0.1.1-alpha.f2bd7316b.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.
@@ -45,7 +45,8 @@ var ErrorType;
45
45
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
46
46
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
47
47
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
48
- ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
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,7 +125,8 @@ 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.";
112
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
128
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
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";
115
132
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
@@ -120,8 +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";
142
+ ConstantString.RegistrationIdPostfix = {
143
+ apiKey: "REGISTRATION_ID",
144
+ oauth2: "CONFIGURATION_ID",
145
+ http: "REGISTRATION_ID",
146
+ openIdConnect: "REGISTRATION_ID",
147
+ };
125
148
  ConstantString.ResponseCodeFor20X = [
126
149
  "200",
127
150
  "201",
@@ -180,9 +203,11 @@ ConstantString.ShortDescriptionMaxLens = 80;
180
203
  ConstantString.FullDescriptionMaxLens = 4000;
181
204
  ConstantString.CommandDescriptionMaxLens = 128;
182
205
  ConstantString.ParameterDescriptionMaxLens = 128;
206
+ ConstantString.ConversationStarterMaxLens = 50;
183
207
  ConstantString.CommandTitleMaxLens = 32;
184
208
  ConstantString.ParameterTitleMaxLens = 32;
185
- ConstantString.SMERequiredParamsMaxNum = 5;
209
+ ConstantString.SMERequiredParamsMaxNum = 5;
210
+ ConstantString.DefaultPluginId = "plugin_1";
186
211
 
187
212
  // Copyright (c) Microsoft Corporation.
188
213
  class Utils {
@@ -197,242 +222,33 @@ class Utils {
197
222
  }
198
223
  return false;
199
224
  }
200
- static checkParameters(paramObject, isCopilot) {
201
- const paramResult = {
202
- requiredNum: 0,
203
- optionalNum: 0,
204
- isValid: true,
205
- };
206
- if (!paramObject) {
207
- return paramResult;
208
- }
209
- for (let i = 0; i < paramObject.length; i++) {
210
- const param = paramObject[i];
211
- const schema = param.schema;
212
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
213
- paramResult.isValid = false;
214
- continue;
215
- }
216
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
217
- if (isCopilot) {
218
- if (isRequiredWithoutDefault) {
219
- paramResult.requiredNum = paramResult.requiredNum + 1;
220
- }
221
- else {
222
- paramResult.optionalNum = paramResult.optionalNum + 1;
223
- }
224
- continue;
225
- }
226
- if (param.in === "header" || param.in === "cookie") {
227
- if (isRequiredWithoutDefault) {
228
- paramResult.isValid = false;
229
- }
230
- continue;
231
- }
232
- if (schema.type !== "boolean" &&
233
- schema.type !== "string" &&
234
- schema.type !== "number" &&
235
- schema.type !== "integer") {
236
- if (isRequiredWithoutDefault) {
237
- paramResult.isValid = false;
238
- }
239
- continue;
240
- }
241
- if (param.in === "query" || param.in === "path") {
242
- if (isRequiredWithoutDefault) {
243
- paramResult.requiredNum = paramResult.requiredNum + 1;
244
- }
245
- else {
246
- paramResult.optionalNum = paramResult.optionalNum + 1;
247
- }
248
- }
249
- }
250
- return paramResult;
225
+ static containMultipleMediaTypes(bodyObject) {
226
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
251
227
  }
252
- static checkPostBody(schema, isRequired = false, isCopilot = false) {
253
- var _a;
254
- const paramResult = {
255
- requiredNum: 0,
256
- optionalNum: 0,
257
- isValid: true,
258
- };
259
- if (Object.keys(schema).length === 0) {
260
- return paramResult;
261
- }
262
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
263
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
264
- paramResult.isValid = false;
265
- return paramResult;
266
- }
267
- if (schema.type === "string" ||
268
- schema.type === "integer" ||
269
- schema.type === "boolean" ||
270
- schema.type === "number") {
271
- if (isRequiredWithoutDefault) {
272
- paramResult.requiredNum = paramResult.requiredNum + 1;
273
- }
274
- else {
275
- paramResult.optionalNum = paramResult.optionalNum + 1;
276
- }
277
- }
278
- else if (schema.type === "object") {
279
- const { properties } = schema;
280
- for (const property in properties) {
281
- let isRequired = false;
282
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
283
- isRequired = true;
284
- }
285
- const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
286
- paramResult.requiredNum += result.requiredNum;
287
- paramResult.optionalNum += result.optionalNum;
288
- paramResult.isValid = paramResult.isValid && result.isValid;
289
- }
290
- }
291
- else {
292
- if (isRequiredWithoutDefault && !isCopilot) {
293
- paramResult.isValid = false;
294
- }
295
- }
296
- return paramResult;
228
+ static isBearerTokenAuth(authScheme) {
229
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
297
230
  }
298
- /**
299
- * Checks if the given API is supported.
300
- * @param {string} method - The HTTP method of the API.
301
- * @param {string} path - The path of the API.
302
- * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
303
- * @returns {boolean} - Returns true if the API is supported, false otherwise.
304
- * @description The following APIs are supported:
305
- * 1. only support Get/Post operation without auth property
306
- * 2. parameter inside query or path only support string, number, boolean and integer
307
- * 3. parameter inside post body only support string, number, boolean, integer and object
308
- * 4. request body + required parameters <= 1
309
- * 5. response body should be “application/json” and not empty, and response code should be 20X
310
- * 6. only support request body with “application/json” content type
311
- */
312
- static isSupportedApi(method, path, spec, options) {
313
- var _a;
314
- const pathObj = spec.paths[path];
315
- method = method.toLocaleLowerCase();
316
- if (pathObj) {
317
- if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
318
- const securities = pathObj[method].security;
319
- const authArray = Utils.getAuthArray(securities, spec);
320
- if (!Utils.isSupportedAuth(authArray, options)) {
321
- return false;
322
- }
323
- const operationObject = pathObj[method];
324
- if (!options.allowMissingId && !operationObject.operationId) {
325
- return false;
326
- }
327
- const paramObject = operationObject.parameters;
328
- const requestBody = operationObject.requestBody;
329
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
330
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
331
- if (mediaTypesCount > 1) {
332
- return false;
333
- }
334
- const responseJson = Utils.getResponseJson(operationObject);
335
- if (Object.keys(responseJson).length === 0) {
336
- return false;
337
- }
338
- let requestBodyParamResult = {
339
- requiredNum: 0,
340
- optionalNum: 0,
341
- isValid: true,
342
- };
343
- const isCopilot = options.projectType === ProjectType.Copilot;
344
- if (requestJsonBody) {
345
- const requestBodySchema = requestJsonBody.schema;
346
- if (isCopilot && requestBodySchema.type !== "object") {
347
- return false;
348
- }
349
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
350
- }
351
- if (!requestBodyParamResult.isValid) {
352
- return false;
353
- }
354
- const paramResult = Utils.checkParameters(paramObject, isCopilot);
355
- if (!paramResult.isValid) {
356
- return false;
357
- }
358
- // Copilot support arbitrary parameters
359
- if (isCopilot) {
360
- return true;
361
- }
362
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
363
- if (options.allowMultipleParameters &&
364
- requestBodyParamResult.requiredNum + paramResult.requiredNum <=
365
- ConstantString.SMERequiredParamsMaxNum) {
366
- return true;
367
- }
368
- return false;
369
- }
370
- else if (requestBodyParamResult.requiredNum +
371
- requestBodyParamResult.optionalNum +
372
- paramResult.requiredNum +
373
- paramResult.optionalNum ===
374
- 0) {
375
- return false;
376
- }
377
- else {
378
- return true;
379
- }
380
- }
381
- }
382
- return false;
231
+ static isAPIKeyAuth(authScheme) {
232
+ return authScheme.type === "apiKey";
383
233
  }
384
- static isSupportedAuth(authSchemaArray, options) {
385
- if (authSchemaArray.length === 0) {
386
- return true;
387
- }
388
- if (options.allowAPIKeyAuth || options.allowOauth2) {
389
- // Currently we don't support multiple auth in one operation
390
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
391
- return false;
392
- }
393
- for (const auths of authSchemaArray) {
394
- if (auths.length === 1) {
395
- if (!options.allowOauth2 &&
396
- options.allowAPIKeyAuth &&
397
- Utils.isAPIKeyAuth(auths[0].authSchema)) {
398
- return true;
399
- }
400
- else if (!options.allowAPIKeyAuth &&
401
- options.allowOauth2 &&
402
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
403
- return true;
404
- }
405
- else if (options.allowAPIKeyAuth &&
406
- options.allowOauth2 &&
407
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
408
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
409
- return true;
410
- }
411
- }
412
- }
413
- }
414
- return false;
415
- }
416
- static isAPIKeyAuth(authSchema) {
417
- return authSchema.type === "apiKey";
418
- }
419
- static isBearerTokenAuth(authSchema) {
420
- return (authSchema.type === "oauth2" ||
421
- authSchema.type === "openIdConnect" ||
422
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
234
+ static isOAuthWithAuthCodeFlow(authScheme) {
235
+ return !!(authScheme.type === "oauth2" &&
236
+ authScheme.flows &&
237
+ authScheme.flows.authorizationCode);
423
238
  }
424
239
  static getAuthArray(securities, spec) {
425
240
  var _a;
426
241
  const result = [];
427
242
  const securitySchemas = (_a = spec.components) === null || _a === void 0 ? void 0 : _a.securitySchemes;
428
- if (securities && securitySchemas) {
429
- for (let i = 0; i < securities.length; i++) {
430
- 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];
431
247
  const authArray = [];
432
248
  for (const name in security) {
433
249
  const auth = securitySchemas[name];
434
250
  authArray.push({
435
- authSchema: auth,
251
+ authScheme: auth,
436
252
  name: name,
437
253
  });
438
254
  }
@@ -444,24 +260,47 @@ class Utils {
444
260
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
445
261
  return result;
446
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
+ }
447
282
  static updateFirstLetter(str) {
448
283
  return str.charAt(0).toUpperCase() + str.slice(1);
449
284
  }
450
285
  static getResponseJson(operationObject) {
451
286
  var _a, _b;
452
287
  let json = {};
288
+ let multipleMediaType = false;
453
289
  for (const code of ConstantString.ResponseCodeFor20X) {
454
290
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
455
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
456
- if (mediaTypesCount > 1) {
457
- return {};
458
- }
459
291
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
292
+ multipleMediaType = false;
460
293
  json = responseObject.content["application/json"];
461
- break;
294
+ if (Utils.containMultipleMediaTypes(responseObject)) {
295
+ multipleMediaType = true;
296
+ json = {};
297
+ }
298
+ else {
299
+ break;
300
+ }
462
301
  }
463
302
  }
464
- return json;
303
+ return { json, multipleMediaType };
465
304
  }
466
305
  static convertPathToCamelCase(path) {
467
306
  const pathSegments = path.split(/[./{]/);
@@ -481,10 +320,10 @@ class Utils {
481
320
  return undefined;
482
321
  }
483
322
  }
484
- static resolveServerUrl(url) {
323
+ static resolveEnv(str) {
485
324
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
486
- let matches = placeHolderReg.exec(url);
487
- let newUrl = url;
325
+ let matches = placeHolderReg.exec(str);
326
+ let newStr = str;
488
327
  while (matches != null) {
489
328
  const envVar = matches[1];
490
329
  const envVal = process.env[envVar];
@@ -492,17 +331,17 @@ class Utils {
492
331
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
493
332
  }
494
333
  else {
495
- newUrl = newUrl.replace(matches[0], envVal);
334
+ newStr = newStr.replace(matches[0], envVal);
496
335
  }
497
- matches = placeHolderReg.exec(url);
336
+ matches = placeHolderReg.exec(str);
498
337
  }
499
- return newUrl;
338
+ return newStr;
500
339
  }
501
340
  static checkServerUrl(servers) {
502
341
  const errors = [];
503
342
  let serverUrl;
504
343
  try {
505
- serverUrl = Utils.resolveServerUrl(servers[0].url);
344
+ serverUrl = Utils.resolveEnv(servers[0].url);
506
345
  }
507
346
  catch (err) {
508
347
  errors.push({
@@ -533,6 +372,7 @@ class Utils {
533
372
  return errors;
534
373
  }
535
374
  static validateServer(spec, options) {
375
+ var _a;
536
376
  const errors = [];
537
377
  let hasTopLevelServers = false;
538
378
  let hasPathLevelServers = false;
@@ -553,7 +393,7 @@ class Utils {
553
393
  }
554
394
  for (const method in methods) {
555
395
  const operationObject = methods[method];
556
- if (Utils.isSupportedApi(method, path, spec, options)) {
396
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
557
397
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
558
398
  hasOperationLevelServers = true;
559
399
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -596,6 +436,7 @@ class Utils {
596
436
  Utils.updateParameterWithInputType(schema, parameter);
597
437
  }
598
438
  if (isRequired && schema.default === undefined) {
439
+ parameter.isRequired = true;
599
440
  requiredParams.push(parameter);
600
441
  }
601
442
  else {
@@ -659,6 +500,7 @@ class Utils {
659
500
  }
660
501
  if (param.in !== "header" && param.in !== "cookie") {
661
502
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
503
+ parameter.isRequired = true;
662
504
  requiredParams.push(parameter);
663
505
  }
664
506
  else {
@@ -678,13 +520,7 @@ class Utils {
678
520
  }
679
521
  }
680
522
  const operationId = operationItem.operationId;
681
- const parameters = [];
682
- if (requiredParams.length !== 0) {
683
- parameters.push(...requiredParams);
684
- }
685
- else {
686
- parameters.push(optionalParams[0]);
687
- }
523
+ const parameters = [...requiredParams, ...optionalParams];
688
524
  const command = {
689
525
  context: ["compose"],
690
526
  type: "query",
@@ -693,105 +529,534 @@ class Utils {
693
529
  parameters: parameters,
694
530
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
695
531
  };
696
- let warning = undefined;
697
- if (requiredParams.length === 0 && optionalParams.length > 1) {
698
- warning = {
699
- type: WarningType.OperationOnlyContainsOptionalParam,
700
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
701
- data: operationId,
702
- };
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 "";
544
+ }
545
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
546
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
547
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
703
548
  }
704
- return [command, warning];
549
+ return safeRegistrationIdEnvName;
705
550
  }
706
- static listSupportedAPIs(spec, options) {
707
- 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;
708
570
  const result = {};
709
571
  for (const path in paths) {
710
572
  const methods = paths[path];
711
573
  for (const method in methods) {
712
- // For developer preview, only support GET operation with only 1 parameter without auth
713
- if (Utils.isSupportedApi(method, path, spec, options)) {
714
- const operationObject = methods[method];
715
- 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
+ };
716
582
  }
717
583
  }
718
584
  }
585
+ this.apiMap = result;
719
586
  return result;
720
587
  }
721
- static validateSpec(spec, parser, isSwaggerFile, options) {
722
- const errors = [];
723
- const warnings = [];
724
- if (isSwaggerFile) {
725
- warnings.push({
726
- type: WarningType.ConvertSwaggerToOpenAPI,
727
- content: ConstantString.ConvertSwaggerToOpenAPI,
728
- });
729
- }
730
- // Server validation
731
- const serverErrors = Utils.validateServer(spec, options);
732
- errors.push(...serverErrors);
733
- // Remote reference not supported
734
- const refPaths = parser.$refs.paths();
735
- // refPaths [0] is the current spec file path
736
- if (refPaths.length > 1) {
737
- errors.push({
738
- type: ErrorType.RemoteRefNotSupported,
739
- content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
740
- 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,
741
595
  });
742
596
  }
743
- // No supported API
744
- const apiMap = Utils.listSupportedAPIs(spec, options);
745
- if (Object.keys(apiMap).length === 0) {
746
- 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({
747
617
  type: ErrorType.NoSupportedApi,
748
618
  content: ConstantString.NoSupportedApi,
619
+ data,
749
620
  });
750
621
  }
622
+ return result;
623
+ }
624
+ validateSpecOperationId() {
625
+ const result = { errors: [], warnings: [] };
626
+ const apiMap = this.listAPIs();
751
627
  // OperationId missing
752
628
  const apisMissingOperationId = [];
753
629
  for (const key in apiMap) {
754
- const pathObjectItem = apiMap[key];
755
- if (!pathObjectItem.operationId) {
630
+ const { operation } = apiMap[key];
631
+ if (!operation.operationId) {
756
632
  apisMissingOperationId.push(key);
757
633
  }
758
634
  }
759
635
  if (apisMissingOperationId.length > 0) {
760
- warnings.push({
636
+ result.warnings.push({
761
637
  type: WarningType.OperationIdMissing,
762
638
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
763
639
  data: apisMissingOperationId,
764
640
  });
765
641
  }
766
- let status = ValidationStatus.Valid;
767
- if (warnings.length > 0 && errors.length === 0) {
768
- 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);
769
681
  }
770
- else if (errors.length > 0) {
771
- 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));
772
686
  }
773
- return {
774
- status,
775
- warnings,
776
- errors,
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: [] };
696
+ }
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: [],
777
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;
778
769
  }
779
- static format(str, ...args) {
780
- let index = 0;
781
- return str.replace(/%s/g, () => {
782
- const arg = args[index++];
783
- return arg !== undefined ? arg : "";
784
- });
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;
785
826
  }
786
- static getSafeRegistrationIdEnvName(authName) {
787
- if (!authName) {
788
- 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
+ }
789
835
  }
790
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
791
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
792
- 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}`);
793
1059
  }
794
- return safeRegistrationIdEnvName;
795
1060
  }
796
1061
  }
797
1062
 
@@ -811,9 +1076,14 @@ class SpecParser {
811
1076
  allowSwagger: false,
812
1077
  allowAPIKeyAuth: false,
813
1078
  allowMultipleParameters: false,
1079
+ allowBearerTokenAuth: false,
814
1080
  allowOauth2: false,
815
1081
  allowMethods: ["get", "post"],
1082
+ allowConversationStarters: false,
1083
+ allowResponseSemantics: false,
1084
+ allowConfirmation: false,
816
1085
  projectType: ProjectType.SME,
1086
+ isGptPlugin: false,
817
1087
  };
818
1088
  this.pathOrSpec = pathOrDoc;
819
1089
  this.parser = new SwaggerParser();
@@ -829,11 +1099,7 @@ class SpecParser {
829
1099
  try {
830
1100
  try {
831
1101
  yield this.loadSpec();
832
- yield this.parser.validate(this.spec, {
833
- validate: {
834
- schema: false,
835
- },
836
- });
1102
+ yield this.parser.validate(this.spec);
837
1103
  }
838
1104
  catch (e) {
839
1105
  return {
@@ -842,16 +1108,46 @@ class SpecParser {
842
1108
  errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
843
1109
  };
844
1110
  }
1111
+ const errors = [];
1112
+ const warnings = [];
845
1113
  if (!this.options.allowSwagger && this.isSwaggerFile) {
846
1114
  return {
847
1115
  status: ValidationStatus.Error,
848
1116
  warnings: [],
849
1117
  errors: [
850
- { type: ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1118
+ {
1119
+ type: ErrorType.SwaggerNotSupported,
1120
+ content: ConstantString.SwaggerNotSupported,
1121
+ },
851
1122
  ],
852
1123
  };
853
1124
  }
854
- 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
+ };
855
1151
  }
856
1152
  catch (err) {
857
1153
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -862,17 +1158,20 @@ class SpecParser {
862
1158
  return __awaiter(this, void 0, void 0, function* () {
863
1159
  try {
864
1160
  yield this.loadSpec();
865
- const apiMap = this.getAllSupportedAPIs(this.spec);
1161
+ const apiMap = this.getAPIs(this.spec);
866
1162
  const apiInfos = [];
867
1163
  for (const key in apiMap) {
868
- const pathObjectItem = apiMap[key];
1164
+ const { operation, isValid } = apiMap[key];
1165
+ if (!isValid) {
1166
+ continue;
1167
+ }
869
1168
  const [method, path] = key.split(" ");
870
- const operationId = pathObjectItem.operationId;
1169
+ const operationId = operation.operationId;
871
1170
  // In Browser environment, this api is by default not support api without operationId
872
1171
  if (!operationId) {
873
1172
  continue;
874
1173
  }
875
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
1174
+ const command = Utils.parseApiInfo(operation, this.options);
876
1175
  const apiInfo = {
877
1176
  method: method,
878
1177
  path: path,
@@ -881,9 +1180,6 @@ class SpecParser {
881
1180
  parameters: command.parameters,
882
1181
  description: command.description,
883
1182
  };
884
- if (warning) {
885
- apiInfo.warning = warning;
886
- }
887
1183
  apiInfos.push(apiInfo);
888
1184
  }
889
1185
  return apiInfos;
@@ -953,13 +1249,18 @@ class SpecParser {
953
1249
  }
954
1250
  });
955
1251
  }
956
- getAllSupportedAPIs(spec) {
957
- if (this.apiMap !== undefined) {
958
- 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;
959
1260
  }
960
- const result = Utils.listSupportedAPIs(spec, this.options);
961
- this.apiMap = result;
962
- return result;
1261
+ const validator = ValidatorFactory.create(spec, this.options);
1262
+ this.validator = validator;
1263
+ return validator;
963
1264
  }
964
1265
  }
965
1266
 
@@ -967,7 +1268,7 @@ class SpecParser {
967
1268
  class AdaptiveCardGenerator {
968
1269
  static generateAdaptiveCard(operationItem) {
969
1270
  try {
970
- const json = Utils.getResponseJson(operationItem);
1271
+ const { json } = Utils.getResponseJson(operationItem);
971
1272
  let cardBody = [];
972
1273
  let schema = json.schema;
973
1274
  let jsonPath = "$";