@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.
@@ -15,7 +15,8 @@ var ErrorType;
15
15
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
16
16
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
17
17
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
18
- ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
18
+ ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
19
+ ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
19
20
  ErrorType["ListFailed"] = "list-failed";
20
21
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
21
22
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -24,6 +25,21 @@ var ErrorType;
24
25
  ErrorType["GenerateFailed"] = "generate-failed";
25
26
  ErrorType["ValidateFailed"] = "validate-failed";
26
27
  ErrorType["GetSpecFailed"] = "get-spec-failed";
28
+ ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
29
+ ErrorType["MissingOperationId"] = "missing-operation-id";
30
+ ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
31
+ ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
32
+ ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
33
+ ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
34
+ ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
35
+ ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
36
+ ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
37
+ ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
38
+ ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
39
+ ErrorType["NoParameter"] = "no-parameter";
40
+ ErrorType["NoAPIInfo"] = "no-api-info";
41
+ ErrorType["MethodNotAllowed"] = "method-not-allowed";
42
+ ErrorType["UrlPathNotExist"] = "url-path-not-exist";
27
43
  ErrorType["Cancelled"] = "cancelled";
28
44
  ErrorType["Unknown"] = "unknown";
29
45
  })(ErrorType || (ErrorType = {}));
@@ -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,7 +95,8 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
79
95
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
80
96
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
81
97
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
82
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
98
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
99
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
83
100
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
84
101
  ConstantString.WrappedCardVersion = "devPreview";
85
102
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
@@ -90,8 +107,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";
112
+ ConstantString.RegistrationIdPostfix = {
113
+ apiKey: "REGISTRATION_ID",
114
+ oauth2: "CONFIGURATION_ID",
115
+ http: "REGISTRATION_ID",
116
+ openIdConnect: "REGISTRATION_ID",
117
+ };
95
118
  ConstantString.ResponseCodeFor20X = [
96
119
  "200",
97
120
  "201",
@@ -150,9 +173,11 @@ ConstantString.ShortDescriptionMaxLens = 80;
150
173
  ConstantString.FullDescriptionMaxLens = 4000;
151
174
  ConstantString.CommandDescriptionMaxLens = 128;
152
175
  ConstantString.ParameterDescriptionMaxLens = 128;
176
+ ConstantString.ConversationStarterMaxLens = 50;
153
177
  ConstantString.CommandTitleMaxLens = 32;
154
178
  ConstantString.ParameterTitleMaxLens = 32;
155
- ConstantString.SMERequiredParamsMaxNum = 5;
179
+ ConstantString.SMERequiredParamsMaxNum = 5;
180
+ ConstantString.DefaultPluginId = "plugin_1";
156
181
 
157
182
  // Copyright (c) Microsoft Corporation.
158
183
  class Utils {
@@ -167,242 +192,33 @@ class Utils {
167
192
  }
168
193
  return false;
169
194
  }
170
- static checkParameters(paramObject, isCopilot) {
171
- const paramResult = {
172
- requiredNum: 0,
173
- optionalNum: 0,
174
- isValid: true,
175
- };
176
- if (!paramObject) {
177
- return paramResult;
178
- }
179
- for (let i = 0; i < paramObject.length; i++) {
180
- const param = paramObject[i];
181
- const schema = param.schema;
182
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
183
- paramResult.isValid = false;
184
- continue;
185
- }
186
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
187
- if (isCopilot) {
188
- if (isRequiredWithoutDefault) {
189
- paramResult.requiredNum = paramResult.requiredNum + 1;
190
- }
191
- else {
192
- paramResult.optionalNum = paramResult.optionalNum + 1;
193
- }
194
- continue;
195
- }
196
- if (param.in === "header" || param.in === "cookie") {
197
- if (isRequiredWithoutDefault) {
198
- paramResult.isValid = false;
199
- }
200
- continue;
201
- }
202
- if (schema.type !== "boolean" &&
203
- schema.type !== "string" &&
204
- schema.type !== "number" &&
205
- schema.type !== "integer") {
206
- if (isRequiredWithoutDefault) {
207
- paramResult.isValid = false;
208
- }
209
- continue;
210
- }
211
- if (param.in === "query" || param.in === "path") {
212
- if (isRequiredWithoutDefault) {
213
- paramResult.requiredNum = paramResult.requiredNum + 1;
214
- }
215
- else {
216
- paramResult.optionalNum = paramResult.optionalNum + 1;
217
- }
218
- }
219
- }
220
- return paramResult;
195
+ static containMultipleMediaTypes(bodyObject) {
196
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
221
197
  }
222
- static checkPostBody(schema, isRequired = false, isCopilot = false) {
223
- var _a;
224
- const paramResult = {
225
- requiredNum: 0,
226
- optionalNum: 0,
227
- isValid: true,
228
- };
229
- if (Object.keys(schema).length === 0) {
230
- return paramResult;
231
- }
232
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
233
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
234
- paramResult.isValid = false;
235
- return paramResult;
236
- }
237
- if (schema.type === "string" ||
238
- schema.type === "integer" ||
239
- schema.type === "boolean" ||
240
- schema.type === "number") {
241
- if (isRequiredWithoutDefault) {
242
- paramResult.requiredNum = paramResult.requiredNum + 1;
243
- }
244
- else {
245
- paramResult.optionalNum = paramResult.optionalNum + 1;
246
- }
247
- }
248
- else if (schema.type === "object") {
249
- const { properties } = schema;
250
- for (const property in properties) {
251
- let isRequired = false;
252
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
253
- isRequired = true;
254
- }
255
- const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
256
- paramResult.requiredNum += result.requiredNum;
257
- paramResult.optionalNum += result.optionalNum;
258
- paramResult.isValid = paramResult.isValid && result.isValid;
259
- }
260
- }
261
- else {
262
- if (isRequiredWithoutDefault && !isCopilot) {
263
- paramResult.isValid = false;
264
- }
265
- }
266
- return paramResult;
198
+ static isBearerTokenAuth(authScheme) {
199
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
267
200
  }
268
- /**
269
- * Checks if the given API is supported.
270
- * @param {string} method - The HTTP method of the API.
271
- * @param {string} path - The path of the API.
272
- * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
273
- * @returns {boolean} - Returns true if the API is supported, false otherwise.
274
- * @description The following APIs are supported:
275
- * 1. only support Get/Post operation without auth property
276
- * 2. parameter inside query or path only support string, number, boolean and integer
277
- * 3. parameter inside post body only support string, number, boolean, integer and object
278
- * 4. request body + required parameters <= 1
279
- * 5. response body should be “application/json” and not empty, and response code should be 20X
280
- * 6. only support request body with “application/json” content type
281
- */
282
- static isSupportedApi(method, path, spec, options) {
283
- var _a;
284
- const pathObj = spec.paths[path];
285
- method = method.toLocaleLowerCase();
286
- if (pathObj) {
287
- if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
288
- const securities = pathObj[method].security;
289
- const authArray = Utils.getAuthArray(securities, spec);
290
- if (!Utils.isSupportedAuth(authArray, options)) {
291
- return false;
292
- }
293
- const operationObject = pathObj[method];
294
- if (!options.allowMissingId && !operationObject.operationId) {
295
- return false;
296
- }
297
- const paramObject = operationObject.parameters;
298
- const requestBody = operationObject.requestBody;
299
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
300
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
301
- if (mediaTypesCount > 1) {
302
- return false;
303
- }
304
- const responseJson = Utils.getResponseJson(operationObject);
305
- if (Object.keys(responseJson).length === 0) {
306
- return false;
307
- }
308
- let requestBodyParamResult = {
309
- requiredNum: 0,
310
- optionalNum: 0,
311
- isValid: true,
312
- };
313
- const isCopilot = options.projectType === ProjectType.Copilot;
314
- if (requestJsonBody) {
315
- const requestBodySchema = requestJsonBody.schema;
316
- if (isCopilot && requestBodySchema.type !== "object") {
317
- return false;
318
- }
319
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
320
- }
321
- if (!requestBodyParamResult.isValid) {
322
- return false;
323
- }
324
- const paramResult = Utils.checkParameters(paramObject, isCopilot);
325
- if (!paramResult.isValid) {
326
- return false;
327
- }
328
- // Copilot support arbitrary parameters
329
- if (isCopilot) {
330
- return true;
331
- }
332
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
333
- if (options.allowMultipleParameters &&
334
- requestBodyParamResult.requiredNum + paramResult.requiredNum <=
335
- ConstantString.SMERequiredParamsMaxNum) {
336
- return true;
337
- }
338
- return false;
339
- }
340
- else if (requestBodyParamResult.requiredNum +
341
- requestBodyParamResult.optionalNum +
342
- paramResult.requiredNum +
343
- paramResult.optionalNum ===
344
- 0) {
345
- return false;
346
- }
347
- else {
348
- return true;
349
- }
350
- }
351
- }
352
- return false;
353
- }
354
- static isSupportedAuth(authSchemaArray, options) {
355
- if (authSchemaArray.length === 0) {
356
- return true;
357
- }
358
- if (options.allowAPIKeyAuth || options.allowOauth2) {
359
- // Currently we don't support multiple auth in one operation
360
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
361
- return false;
362
- }
363
- for (const auths of authSchemaArray) {
364
- if (auths.length === 1) {
365
- if (!options.allowOauth2 &&
366
- options.allowAPIKeyAuth &&
367
- Utils.isAPIKeyAuth(auths[0].authSchema)) {
368
- return true;
369
- }
370
- else if (!options.allowAPIKeyAuth &&
371
- options.allowOauth2 &&
372
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
373
- return true;
374
- }
375
- else if (options.allowAPIKeyAuth &&
376
- options.allowOauth2 &&
377
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
378
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
379
- return true;
380
- }
381
- }
382
- }
383
- }
384
- return false;
385
- }
386
- static isAPIKeyAuth(authSchema) {
387
- return authSchema.type === "apiKey";
201
+ static isAPIKeyAuth(authScheme) {
202
+ return authScheme.type === "apiKey";
388
203
  }
389
- static isBearerTokenAuth(authSchema) {
390
- return (authSchema.type === "oauth2" ||
391
- authSchema.type === "openIdConnect" ||
392
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
204
+ static isOAuthWithAuthCodeFlow(authScheme) {
205
+ return !!(authScheme.type === "oauth2" &&
206
+ authScheme.flows &&
207
+ authScheme.flows.authorizationCode);
393
208
  }
394
209
  static getAuthArray(securities, spec) {
395
210
  var _a;
396
211
  const result = [];
397
212
  const securitySchemas = (_a = spec.components) === null || _a === void 0 ? void 0 : _a.securitySchemes;
398
- if (securities && securitySchemas) {
399
- for (let i = 0; i < securities.length; i++) {
400
- 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];
401
217
  const authArray = [];
402
218
  for (const name in security) {
403
219
  const auth = securitySchemas[name];
404
220
  authArray.push({
405
- authSchema: auth,
221
+ authScheme: auth,
406
222
  name: name,
407
223
  });
408
224
  }
@@ -414,24 +230,47 @@ class Utils {
414
230
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
415
231
  return result;
416
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
+ }
417
252
  static updateFirstLetter(str) {
418
253
  return str.charAt(0).toUpperCase() + str.slice(1);
419
254
  }
420
255
  static getResponseJson(operationObject) {
421
256
  var _a, _b;
422
257
  let json = {};
258
+ let multipleMediaType = false;
423
259
  for (const code of ConstantString.ResponseCodeFor20X) {
424
260
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
425
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
426
- if (mediaTypesCount > 1) {
427
- return {};
428
- }
429
261
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
262
+ multipleMediaType = false;
430
263
  json = responseObject.content["application/json"];
431
- break;
264
+ if (Utils.containMultipleMediaTypes(responseObject)) {
265
+ multipleMediaType = true;
266
+ json = {};
267
+ }
268
+ else {
269
+ break;
270
+ }
432
271
  }
433
272
  }
434
- return json;
273
+ return { json, multipleMediaType };
435
274
  }
436
275
  static convertPathToCamelCase(path) {
437
276
  const pathSegments = path.split(/[./{]/);
@@ -451,10 +290,10 @@ class Utils {
451
290
  return undefined;
452
291
  }
453
292
  }
454
- static resolveServerUrl(url) {
293
+ static resolveEnv(str) {
455
294
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
456
- let matches = placeHolderReg.exec(url);
457
- let newUrl = url;
295
+ let matches = placeHolderReg.exec(str);
296
+ let newStr = str;
458
297
  while (matches != null) {
459
298
  const envVar = matches[1];
460
299
  const envVal = process.env[envVar];
@@ -462,17 +301,17 @@ class Utils {
462
301
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
463
302
  }
464
303
  else {
465
- newUrl = newUrl.replace(matches[0], envVal);
304
+ newStr = newStr.replace(matches[0], envVal);
466
305
  }
467
- matches = placeHolderReg.exec(url);
306
+ matches = placeHolderReg.exec(str);
468
307
  }
469
- return newUrl;
308
+ return newStr;
470
309
  }
471
310
  static checkServerUrl(servers) {
472
311
  const errors = [];
473
312
  let serverUrl;
474
313
  try {
475
- serverUrl = Utils.resolveServerUrl(servers[0].url);
314
+ serverUrl = Utils.resolveEnv(servers[0].url);
476
315
  }
477
316
  catch (err) {
478
317
  errors.push({
@@ -503,6 +342,7 @@ class Utils {
503
342
  return errors;
504
343
  }
505
344
  static validateServer(spec, options) {
345
+ var _a;
506
346
  const errors = [];
507
347
  let hasTopLevelServers = false;
508
348
  let hasPathLevelServers = false;
@@ -523,7 +363,7 @@ class Utils {
523
363
  }
524
364
  for (const method in methods) {
525
365
  const operationObject = methods[method];
526
- if (Utils.isSupportedApi(method, path, spec, options)) {
366
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
527
367
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
528
368
  hasOperationLevelServers = true;
529
369
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -566,6 +406,7 @@ class Utils {
566
406
  Utils.updateParameterWithInputType(schema, parameter);
567
407
  }
568
408
  if (isRequired && schema.default === undefined) {
409
+ parameter.isRequired = true;
569
410
  requiredParams.push(parameter);
570
411
  }
571
412
  else {
@@ -629,6 +470,7 @@ class Utils {
629
470
  }
630
471
  if (param.in !== "header" && param.in !== "cookie") {
631
472
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
473
+ parameter.isRequired = true;
632
474
  requiredParams.push(parameter);
633
475
  }
634
476
  else {
@@ -648,13 +490,7 @@ class Utils {
648
490
  }
649
491
  }
650
492
  const operationId = operationItem.operationId;
651
- const parameters = [];
652
- if (requiredParams.length !== 0) {
653
- parameters.push(...requiredParams);
654
- }
655
- else {
656
- parameters.push(optionalParams[0]);
657
- }
493
+ const parameters = [...requiredParams, ...optionalParams];
658
494
  const command = {
659
495
  context: ["compose"],
660
496
  type: "query",
@@ -663,105 +499,534 @@ class Utils {
663
499
  parameters: parameters,
664
500
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
665
501
  };
666
- let warning = undefined;
667
- if (requiredParams.length === 0 && optionalParams.length > 1) {
668
- warning = {
669
- type: WarningType.OperationOnlyContainsOptionalParam,
670
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
671
- data: operationId,
672
- };
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 "";
673
514
  }
674
- return [command, warning];
515
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
516
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
517
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
518
+ }
519
+ return safeRegistrationIdEnvName;
675
520
  }
676
- static listSupportedAPIs(spec, options) {
677
- 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;
678
540
  const result = {};
679
541
  for (const path in paths) {
680
542
  const methods = paths[path];
681
543
  for (const method in methods) {
682
- // For developer preview, only support GET operation with only 1 parameter without auth
683
- if (Utils.isSupportedApi(method, path, spec, options)) {
684
- const operationObject = methods[method];
685
- result[`${method.toUpperCase()} ${path}`] = operationObject;
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
+ };
686
552
  }
687
553
  }
688
554
  }
555
+ this.apiMap = result;
689
556
  return result;
690
557
  }
691
- static validateSpec(spec, parser, isSwaggerFile, options) {
692
- const errors = [];
693
- const warnings = [];
694
- if (isSwaggerFile) {
695
- warnings.push({
696
- type: WarningType.ConvertSwaggerToOpenAPI,
697
- content: ConstantString.ConvertSwaggerToOpenAPI,
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,
698
565
  });
699
566
  }
700
- // Server validation
701
- const serverErrors = Utils.validateServer(spec, options);
702
- errors.push(...serverErrors);
703
- // Remote reference not supported
704
- const refPaths = parser.$refs.paths();
705
- // refPaths [0] is the current spec file path
706
- if (refPaths.length > 1) {
707
- errors.push({
708
- type: ErrorType.RemoteRefNotSupported,
709
- content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
710
- data: refPaths,
711
- });
712
- }
713
- // No supported API
714
- const apiMap = Utils.listSupportedAPIs(spec, options);
715
- if (Object.keys(apiMap).length === 0) {
716
- 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({
717
587
  type: ErrorType.NoSupportedApi,
718
588
  content: ConstantString.NoSupportedApi,
589
+ data,
719
590
  });
720
591
  }
592
+ return result;
593
+ }
594
+ validateSpecOperationId() {
595
+ const result = { errors: [], warnings: [] };
596
+ const apiMap = this.listAPIs();
721
597
  // OperationId missing
722
598
  const apisMissingOperationId = [];
723
599
  for (const key in apiMap) {
724
- const pathObjectItem = apiMap[key];
725
- if (!pathObjectItem.operationId) {
600
+ const { operation } = apiMap[key];
601
+ if (!operation.operationId) {
726
602
  apisMissingOperationId.push(key);
727
603
  }
728
604
  }
729
605
  if (apisMissingOperationId.length > 0) {
730
- warnings.push({
606
+ result.warnings.push({
731
607
  type: WarningType.OperationIdMissing,
732
608
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
733
609
  data: apisMissingOperationId,
734
610
  });
735
611
  }
736
- let status = ValidationStatus.Valid;
737
- if (warnings.length > 0 && errors.length === 0) {
738
- 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
+ }
739
642
  }
740
- else if (errors.length > 0) {
741
- 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);
742
651
  }
743
- return {
744
- status,
745
- warnings,
746
- 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: [],
747
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;
748
739
  }
749
- static format(str, ...args) {
750
- let index = 0;
751
- return str.replace(/%s/g, () => {
752
- const arg = args[index++];
753
- return arg !== undefined ? arg : "";
754
- });
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;
755
796
  }
756
- static getSafeRegistrationIdEnvName(authName) {
757
- if (!authName) {
758
- 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
+ }
759
805
  }
760
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
761
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
762
- 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}`);
763
1029
  }
764
- return safeRegistrationIdEnvName;
765
1030
  }
766
1031
  }
767
1032
 
@@ -781,9 +1046,14 @@ class SpecParser {
781
1046
  allowSwagger: false,
782
1047
  allowAPIKeyAuth: false,
783
1048
  allowMultipleParameters: false,
1049
+ allowBearerTokenAuth: false,
784
1050
  allowOauth2: false,
785
1051
  allowMethods: ["get", "post"],
1052
+ allowConversationStarters: false,
1053
+ allowResponseSemantics: false,
1054
+ allowConfirmation: false,
786
1055
  projectType: ProjectType.SME,
1056
+ isGptPlugin: false,
787
1057
  };
788
1058
  this.pathOrSpec = pathOrDoc;
789
1059
  this.parser = new SwaggerParser();
@@ -798,11 +1068,7 @@ class SpecParser {
798
1068
  try {
799
1069
  try {
800
1070
  await this.loadSpec();
801
- await this.parser.validate(this.spec, {
802
- validate: {
803
- schema: false,
804
- },
805
- });
1071
+ await this.parser.validate(this.spec);
806
1072
  }
807
1073
  catch (e) {
808
1074
  return {
@@ -811,16 +1077,46 @@ class SpecParser {
811
1077
  errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
812
1078
  };
813
1079
  }
1080
+ const errors = [];
1081
+ const warnings = [];
814
1082
  if (!this.options.allowSwagger && this.isSwaggerFile) {
815
1083
  return {
816
1084
  status: ValidationStatus.Error,
817
1085
  warnings: [],
818
1086
  errors: [
819
- { type: ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1087
+ {
1088
+ type: ErrorType.SwaggerNotSupported,
1089
+ content: ConstantString.SwaggerNotSupported,
1090
+ },
820
1091
  ],
821
1092
  };
822
1093
  }
823
- 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
+ };
824
1120
  }
825
1121
  catch (err) {
826
1122
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -829,17 +1125,20 @@ class SpecParser {
829
1125
  async listSupportedAPIInfo() {
830
1126
  try {
831
1127
  await this.loadSpec();
832
- const apiMap = this.getAllSupportedAPIs(this.spec);
1128
+ const apiMap = this.getAPIs(this.spec);
833
1129
  const apiInfos = [];
834
1130
  for (const key in apiMap) {
835
- const pathObjectItem = apiMap[key];
1131
+ const { operation, isValid } = apiMap[key];
1132
+ if (!isValid) {
1133
+ continue;
1134
+ }
836
1135
  const [method, path] = key.split(" ");
837
- const operationId = pathObjectItem.operationId;
1136
+ const operationId = operation.operationId;
838
1137
  // In Browser environment, this api is by default not support api without operationId
839
1138
  if (!operationId) {
840
1139
  continue;
841
1140
  }
842
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
1141
+ const command = Utils.parseApiInfo(operation, this.options);
843
1142
  const apiInfo = {
844
1143
  method: method,
845
1144
  path: path,
@@ -848,9 +1147,6 @@ class SpecParser {
848
1147
  parameters: command.parameters,
849
1148
  description: command.description,
850
1149
  };
851
- if (warning) {
852
- apiInfo.warning = warning;
853
- }
854
1150
  apiInfos.push(apiInfo);
855
1151
  }
856
1152
  return apiInfos;
@@ -909,13 +1205,18 @@ class SpecParser {
909
1205
  this.spec = (await this.parser.dereference(clonedUnResolveSpec));
910
1206
  }
911
1207
  }
912
- getAllSupportedAPIs(spec) {
913
- if (this.apiMap !== undefined) {
914
- 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;
915
1216
  }
916
- const result = Utils.listSupportedAPIs(spec, this.options);
917
- this.apiMap = result;
918
- return result;
1217
+ const validator = ValidatorFactory.create(spec, this.options);
1218
+ this.validator = validator;
1219
+ return validator;
919
1220
  }
920
1221
  }
921
1222
 
@@ -923,7 +1224,7 @@ class SpecParser {
923
1224
  class AdaptiveCardGenerator {
924
1225
  static generateAdaptiveCard(operationItem) {
925
1226
  try {
926
- const json = Utils.getResponseJson(operationItem);
1227
+ const { json } = Utils.getResponseJson(operationItem);
927
1228
  let cardBody = [];
928
1229
  let schema = json.schema;
929
1230
  let jsonPath = "$";