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