@microsoft/m365-spec-parser 0.1.1-alpha.4f2290daa.0 → 0.1.1-alpha.5fc8ceacd.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.
@@ -208,7 +208,8 @@ ConstantString.CommandDescriptionMaxLens = 128;
208
208
  ConstantString.ParameterDescriptionMaxLens = 128;
209
209
  ConstantString.CommandTitleMaxLens = 32;
210
210
  ConstantString.ParameterTitleMaxLens = 32;
211
- ConstantString.SMERequiredParamsMaxNum = 5;
211
+ ConstantString.SMERequiredParamsMaxNum = 5;
212
+ ConstantString.DefaultPluginId = "plugin_1";
212
213
 
213
214
  // Copyright (c) Microsoft Corporation.
214
215
  class SpecParserError extends Error {
@@ -231,249 +232,9 @@ class Utils {
231
232
  }
232
233
  return false;
233
234
  }
234
- static checkParameters(paramObject, isCopilot) {
235
- const paramResult = {
236
- requiredNum: 0,
237
- optionalNum: 0,
238
- isValid: true,
239
- reason: [],
240
- };
241
- if (!paramObject) {
242
- return paramResult;
243
- }
244
- for (let i = 0; i < paramObject.length; i++) {
245
- const param = paramObject[i];
246
- const schema = param.schema;
247
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
248
- paramResult.isValid = false;
249
- paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
250
- continue;
251
- }
252
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
253
- if (isCopilot) {
254
- if (isRequiredWithoutDefault) {
255
- paramResult.requiredNum = paramResult.requiredNum + 1;
256
- }
257
- else {
258
- paramResult.optionalNum = paramResult.optionalNum + 1;
259
- }
260
- continue;
261
- }
262
- if (param.in === "header" || param.in === "cookie") {
263
- if (isRequiredWithoutDefault) {
264
- paramResult.isValid = false;
265
- paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
266
- }
267
- continue;
268
- }
269
- if (schema.type !== "boolean" &&
270
- schema.type !== "string" &&
271
- schema.type !== "number" &&
272
- schema.type !== "integer") {
273
- if (isRequiredWithoutDefault) {
274
- paramResult.isValid = false;
275
- paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
276
- }
277
- continue;
278
- }
279
- if (param.in === "query" || param.in === "path") {
280
- if (isRequiredWithoutDefault) {
281
- paramResult.requiredNum = paramResult.requiredNum + 1;
282
- }
283
- else {
284
- paramResult.optionalNum = paramResult.optionalNum + 1;
285
- }
286
- }
287
- }
288
- return paramResult;
289
- }
290
- static checkPostBody(schema, isRequired = false, isCopilot = false) {
291
- var _a;
292
- const paramResult = {
293
- requiredNum: 0,
294
- optionalNum: 0,
295
- isValid: true,
296
- reason: [],
297
- };
298
- if (Object.keys(schema).length === 0) {
299
- return paramResult;
300
- }
301
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
302
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
303
- paramResult.isValid = false;
304
- paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
305
- return paramResult;
306
- }
307
- if (schema.type === "string" ||
308
- schema.type === "integer" ||
309
- schema.type === "boolean" ||
310
- schema.type === "number") {
311
- if (isRequiredWithoutDefault) {
312
- paramResult.requiredNum = paramResult.requiredNum + 1;
313
- }
314
- else {
315
- paramResult.optionalNum = paramResult.optionalNum + 1;
316
- }
317
- }
318
- else if (schema.type === "object") {
319
- const { properties } = schema;
320
- for (const property in properties) {
321
- let isRequired = false;
322
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
323
- isRequired = true;
324
- }
325
- const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
326
- paramResult.requiredNum += result.requiredNum;
327
- paramResult.optionalNum += result.optionalNum;
328
- paramResult.isValid = paramResult.isValid && result.isValid;
329
- paramResult.reason.push(...result.reason);
330
- }
331
- }
332
- else {
333
- if (isRequiredWithoutDefault && !isCopilot) {
334
- paramResult.isValid = false;
335
- paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
336
- }
337
- }
338
- return paramResult;
339
- }
340
235
  static containMultipleMediaTypes(bodyObject) {
341
236
  return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
342
237
  }
343
- /**
344
- * Checks if the given API is supported.
345
- * @param {string} method - The HTTP method of the API.
346
- * @param {string} path - The path of the API.
347
- * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
348
- * @returns {boolean} - Returns true if the API is supported, false otherwise.
349
- * @description The following APIs are supported:
350
- * 1. only support Get/Post operation without auth property
351
- * 2. parameter inside query or path only support string, number, boolean and integer
352
- * 3. parameter inside post body only support string, number, boolean, integer and object
353
- * 4. request body + required parameters <= 1
354
- * 5. response body should be “application/json” and not empty, and response code should be 20X
355
- * 6. only support request body with “application/json” content type
356
- */
357
- static isSupportedApi(method, path, spec, options) {
358
- var _a;
359
- const result = { isValid: true, reason: [] };
360
- method = method.toLocaleLowerCase();
361
- if (options.allowMethods && !options.allowMethods.includes(method)) {
362
- result.isValid = false;
363
- result.reason.push(exports.ErrorType.MethodNotAllowed);
364
- return result;
365
- }
366
- const pathObj = spec.paths[path];
367
- if (!pathObj || !pathObj[method]) {
368
- result.isValid = false;
369
- result.reason.push(exports.ErrorType.UrlPathNotExist);
370
- return result;
371
- }
372
- const securities = pathObj[method].security;
373
- const isTeamsAi = options.projectType === exports.ProjectType.TeamsAi;
374
- const isCopilot = options.projectType === exports.ProjectType.Copilot;
375
- // Teams AI project doesn't care about auth, it will use authProvider for user to implement
376
- if (!isTeamsAi) {
377
- const authArray = Utils.getAuthArray(securities, spec);
378
- const authCheckResult = Utils.isSupportedAuth(authArray, options);
379
- if (!authCheckResult.isValid) {
380
- result.reason.push(...authCheckResult.reason);
381
- }
382
- }
383
- const operationObject = pathObj[method];
384
- if (!options.allowMissingId && !operationObject.operationId) {
385
- result.reason.push(exports.ErrorType.MissingOperationId);
386
- }
387
- const rootServer = spec.servers && spec.servers[0];
388
- const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
389
- const operationServer = operationObject.servers && operationObject.servers[0];
390
- const serverUrl = operationServer || methodServer || rootServer;
391
- if (!serverUrl) {
392
- result.reason.push(exports.ErrorType.NoServerInformation);
393
- }
394
- else {
395
- const serverValidateResult = Utils.checkServerUrl([serverUrl]);
396
- result.reason.push(...serverValidateResult.map((item) => item.type));
397
- }
398
- const paramObject = operationObject.parameters;
399
- const requestBody = operationObject.requestBody;
400
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
401
- if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
402
- result.reason.push(exports.ErrorType.PostBodyContainMultipleMediaTypes);
403
- }
404
- const { json, multipleMediaType } = Utils.getResponseJson(operationObject, isTeamsAi);
405
- if (multipleMediaType && !isTeamsAi) {
406
- result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
407
- }
408
- else if (Object.keys(json).length === 0) {
409
- result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
410
- }
411
- // Teams AI project doesn't care about request parameters/body
412
- if (!isTeamsAi) {
413
- let requestBodyParamResult = {
414
- requiredNum: 0,
415
- optionalNum: 0,
416
- isValid: true,
417
- reason: [],
418
- };
419
- if (requestJsonBody) {
420
- const requestBodySchema = requestJsonBody.schema;
421
- if (isCopilot && requestBodySchema.type !== "object") {
422
- result.reason.push(exports.ErrorType.PostBodySchemaIsNotJson);
423
- }
424
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
425
- if (!requestBodyParamResult.isValid && requestBodyParamResult.reason) {
426
- result.reason.push(...requestBodyParamResult.reason);
427
- }
428
- }
429
- const paramResult = Utils.checkParameters(paramObject, isCopilot);
430
- if (!paramResult.isValid && paramResult.reason) {
431
- result.reason.push(...paramResult.reason);
432
- }
433
- // Copilot support arbitrary parameters
434
- if (!isCopilot && paramResult.isValid && requestBodyParamResult.isValid) {
435
- const totalRequiredParams = requestBodyParamResult.requiredNum + paramResult.requiredNum;
436
- const totalParams = totalRequiredParams + requestBodyParamResult.optionalNum + paramResult.optionalNum;
437
- if (totalRequiredParams > 1) {
438
- if (!options.allowMultipleParameters ||
439
- totalRequiredParams > ConstantString.SMERequiredParamsMaxNum) {
440
- result.reason.push(exports.ErrorType.ExceededRequiredParamsLimit);
441
- }
442
- }
443
- else if (totalParams === 0) {
444
- result.reason.push(exports.ErrorType.NoParameter);
445
- }
446
- }
447
- }
448
- if (result.reason.length > 0) {
449
- result.isValid = false;
450
- }
451
- return result;
452
- }
453
- static isSupportedAuth(authSchemeArray, options) {
454
- if (authSchemeArray.length === 0) {
455
- return { isValid: true, reason: [] };
456
- }
457
- if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
458
- // Currently we don't support multiple auth in one operation
459
- if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
460
- return {
461
- isValid: false,
462
- reason: [exports.ErrorType.MultipleAuthNotSupported],
463
- };
464
- }
465
- for (const auths of authSchemeArray) {
466
- if (auths.length === 1) {
467
- if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
468
- (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
469
- (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
470
- return { isValid: true, reason: [] };
471
- }
472
- }
473
- }
474
- }
475
- return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
476
- }
477
238
  static isBearerTokenAuth(authScheme) {
478
239
  return authScheme.type === "http" && authScheme.scheme === "bearer";
479
240
  }
@@ -481,10 +242,9 @@ class Utils {
481
242
  return authScheme.type === "apiKey";
482
243
  }
483
244
  static isOAuthWithAuthCodeFlow(authScheme) {
484
- if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
485
- return true;
486
- }
487
- return false;
245
+ return !!(authScheme.type === "oauth2" &&
246
+ authScheme.flows &&
247
+ authScheme.flows.authorizationCode);
488
248
  }
489
249
  static getAuthArray(securities, spec) {
490
250
  var _a;
@@ -512,7 +272,7 @@ class Utils {
512
272
  static updateFirstLetter(str) {
513
273
  return str.charAt(0).toUpperCase() + str.slice(1);
514
274
  }
515
- static getResponseJson(operationObject, isTeamsAiProject = false) {
275
+ static getResponseJson(operationObject) {
516
276
  var _a, _b;
517
277
  let json = {};
518
278
  let multipleMediaType = false;
@@ -523,9 +283,6 @@ class Utils {
523
283
  json = responseObject.content["application/json"];
524
284
  if (Utils.containMultipleMediaTypes(responseObject)) {
525
285
  multipleMediaType = true;
526
- if (isTeamsAiProject) {
527
- break;
528
- }
529
286
  json = {};
530
287
  }
531
288
  else {
@@ -764,16 +521,49 @@ class Utils {
764
521
  };
765
522
  return command;
766
523
  }
767
- static listAPIs(spec, options) {
524
+ static format(str, ...args) {
525
+ let index = 0;
526
+ return str.replace(/%s/g, () => {
527
+ const arg = args[index++];
528
+ return arg !== undefined ? arg : "";
529
+ });
530
+ }
531
+ static getSafeRegistrationIdEnvName(authName) {
532
+ if (!authName) {
533
+ return "";
534
+ }
535
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
536
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
537
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
538
+ }
539
+ return safeRegistrationIdEnvName;
540
+ }
541
+ static getServerObject(spec, method, path) {
542
+ const pathObj = spec.paths[path];
543
+ const operationObject = pathObj[method];
544
+ const rootServer = spec.servers && spec.servers[0];
545
+ const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
546
+ const operationServer = operationObject.servers && operationObject.servers[0];
547
+ const serverUrl = operationServer || methodServer || rootServer;
548
+ return serverUrl;
549
+ }
550
+ }
551
+
552
+ // Copyright (c) Microsoft Corporation.
553
+ class Validator {
554
+ listAPIs() {
768
555
  var _a;
769
- const paths = spec.paths;
556
+ if (this.apiMap) {
557
+ return this.apiMap;
558
+ }
559
+ const paths = this.spec.paths;
770
560
  const result = {};
771
561
  for (const path in paths) {
772
562
  const methods = paths[path];
773
563
  for (const method in methods) {
774
564
  const operationObject = methods[method];
775
- if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
776
- const validateResult = Utils.isSupportedApi(method, path, spec, options);
565
+ if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
566
+ const validateResult = this.validateAPI(method, path);
777
567
  result[`${method.toUpperCase()} ${path}`] = {
778
568
  operation: operationObject,
779
569
  isValid: validateResult.isValid,
@@ -782,38 +572,48 @@ class Utils {
782
572
  }
783
573
  }
784
574
  }
575
+ this.apiMap = result;
785
576
  return result;
786
577
  }
787
- static validateSpec(spec, parser, isSwaggerFile, options) {
788
- const errors = [];
789
- const warnings = [];
790
- const apiMap = Utils.listAPIs(spec, options);
791
- if (isSwaggerFile) {
792
- warnings.push({
793
- type: exports.WarningType.ConvertSwaggerToOpenAPI,
794
- content: ConstantString.ConvertSwaggerToOpenAPI,
795
- });
796
- }
797
- const serverErrors = Utils.validateServer(spec, options);
798
- errors.push(...serverErrors);
799
- // Remote reference not supported
800
- const refPaths = parser.$refs.paths();
801
- // refPaths [0] is the current spec file path
802
- if (refPaths.length > 1) {
803
- errors.push({
804
- type: exports.ErrorType.RemoteRefNotSupported,
805
- content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
806
- data: refPaths,
578
+ validateSpecVersion() {
579
+ const result = { errors: [], warnings: [] };
580
+ if (this.spec.openapi >= "3.1.0") {
581
+ result.errors.push({
582
+ type: exports.ErrorType.SpecVersionNotSupported,
583
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
584
+ data: this.spec.openapi,
807
585
  });
808
586
  }
809
- // No supported API
587
+ return result;
588
+ }
589
+ validateSpecServer() {
590
+ const result = { errors: [], warnings: [] };
591
+ const serverErrors = Utils.validateServer(this.spec, this.options);
592
+ result.errors.push(...serverErrors);
593
+ return result;
594
+ }
595
+ validateSpecNoSupportAPI() {
596
+ const result = { errors: [], warnings: [] };
597
+ const apiMap = this.listAPIs();
810
598
  const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
811
599
  if (validAPIs.length === 0) {
812
- errors.push({
600
+ const data = [];
601
+ for (const key in apiMap) {
602
+ const { reason } = apiMap[key];
603
+ const apiInvalidReason = { api: key, reason: reason };
604
+ data.push(apiInvalidReason);
605
+ }
606
+ result.errors.push({
813
607
  type: exports.ErrorType.NoSupportedApi,
814
608
  content: ConstantString.NoSupportedApi,
609
+ data,
815
610
  });
816
611
  }
612
+ return result;
613
+ }
614
+ validateSpecOperationId() {
615
+ const result = { errors: [], warnings: [] };
616
+ const apiMap = this.listAPIs();
817
617
  // OperationId missing
818
618
  const apisMissingOperationId = [];
819
619
  for (const key in apiMap) {
@@ -823,54 +623,431 @@ class Utils {
823
623
  }
824
624
  }
825
625
  if (apisMissingOperationId.length > 0) {
826
- warnings.push({
626
+ result.warnings.push({
827
627
  type: exports.WarningType.OperationIdMissing,
828
628
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
829
629
  data: apisMissingOperationId,
830
630
  });
831
631
  }
832
- let status = exports.ValidationStatus.Valid;
833
- if (warnings.length > 0 && errors.length === 0) {
834
- status = exports.ValidationStatus.Warning;
632
+ return result;
633
+ }
634
+ validateMethodAndPath(method, path) {
635
+ const result = { isValid: true, reason: [] };
636
+ if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
637
+ result.isValid = false;
638
+ result.reason.push(exports.ErrorType.MethodNotAllowed);
639
+ return result;
835
640
  }
836
- else if (errors.length > 0) {
837
- status = exports.ValidationStatus.Error;
641
+ const pathObj = this.spec.paths[path];
642
+ if (!pathObj || !pathObj[method]) {
643
+ result.isValid = false;
644
+ result.reason.push(exports.ErrorType.UrlPathNotExist);
645
+ return result;
838
646
  }
839
- return {
840
- status,
841
- warnings,
842
- errors,
843
- };
647
+ return result;
844
648
  }
845
- static format(str, ...args) {
846
- let index = 0;
847
- return str.replace(/%s/g, () => {
848
- const arg = args[index++];
849
- return arg !== undefined ? arg : "";
850
- });
649
+ validateResponse(method, path) {
650
+ const result = { isValid: true, reason: [] };
651
+ const operationObject = this.spec.paths[path][method];
652
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
653
+ // only support response body only contains “application/json” content type
654
+ if (multipleMediaType) {
655
+ result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
656
+ }
657
+ else if (Object.keys(json).length === 0) {
658
+ // response body should not be empty
659
+ result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
660
+ }
661
+ return result;
851
662
  }
852
- static getSafeRegistrationIdEnvName(authName) {
853
- if (!authName) {
854
- return "";
663
+ validateServer(method, path) {
664
+ const result = { isValid: true, reason: [] };
665
+ const serverObj = Utils.getServerObject(this.spec, method, path);
666
+ if (!serverObj) {
667
+ // should contain server URL
668
+ result.reason.push(exports.ErrorType.NoServerInformation);
855
669
  }
856
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
857
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
858
- safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
670
+ else {
671
+ // server url should be absolute url with https protocol
672
+ const serverValidateResult = Utils.checkServerUrl([serverObj]);
673
+ result.reason.push(...serverValidateResult.map((item) => item.type));
859
674
  }
860
- return safeRegistrationIdEnvName;
675
+ return result;
861
676
  }
862
- static getAllAPICount(spec) {
863
- let count = 0;
864
- const paths = spec.paths;
865
- for (const path in paths) {
866
- const methods = paths[path];
867
- for (const method in methods) {
868
- if (ConstantString.AllOperationMethods.includes(method)) {
869
- count++;
677
+ validateAuth(method, path) {
678
+ const pathObj = this.spec.paths[path];
679
+ const operationObject = pathObj[method];
680
+ const securities = operationObject.security;
681
+ const authSchemeArray = Utils.getAuthArray(securities, this.spec);
682
+ if (authSchemeArray.length === 0) {
683
+ return { isValid: true, reason: [] };
684
+ }
685
+ if (this.options.allowAPIKeyAuth ||
686
+ this.options.allowOauth2 ||
687
+ this.options.allowBearerTokenAuth) {
688
+ // Currently we don't support multiple auth in one operation
689
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
690
+ return {
691
+ isValid: false,
692
+ reason: [exports.ErrorType.MultipleAuthNotSupported],
693
+ };
694
+ }
695
+ for (const auths of authSchemeArray) {
696
+ if (auths.length === 1) {
697
+ if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
698
+ (this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
699
+ (this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
700
+ return { isValid: true, reason: [] };
701
+ }
702
+ }
703
+ }
704
+ }
705
+ return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
706
+ }
707
+ checkPostBodySchema(schema, isRequired = false) {
708
+ var _a;
709
+ const paramResult = {
710
+ requiredNum: 0,
711
+ optionalNum: 0,
712
+ isValid: true,
713
+ reason: [],
714
+ };
715
+ if (Object.keys(schema).length === 0) {
716
+ return paramResult;
717
+ }
718
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
719
+ const isCopilot = this.projectType === exports.ProjectType.Copilot;
720
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
721
+ paramResult.isValid = false;
722
+ paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
723
+ return paramResult;
724
+ }
725
+ if (schema.type === "string" ||
726
+ schema.type === "integer" ||
727
+ schema.type === "boolean" ||
728
+ schema.type === "number") {
729
+ if (isRequiredWithoutDefault) {
730
+ paramResult.requiredNum = paramResult.requiredNum + 1;
731
+ }
732
+ else {
733
+ paramResult.optionalNum = paramResult.optionalNum + 1;
734
+ }
735
+ }
736
+ else if (schema.type === "object") {
737
+ const { properties } = schema;
738
+ for (const property in properties) {
739
+ let isRequired = false;
740
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
741
+ isRequired = true;
742
+ }
743
+ const result = this.checkPostBodySchema(properties[property], isRequired);
744
+ paramResult.requiredNum += result.requiredNum;
745
+ paramResult.optionalNum += result.optionalNum;
746
+ paramResult.isValid = paramResult.isValid && result.isValid;
747
+ paramResult.reason.push(...result.reason);
748
+ }
749
+ }
750
+ else {
751
+ if (isRequiredWithoutDefault && !isCopilot) {
752
+ paramResult.isValid = false;
753
+ paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
754
+ }
755
+ }
756
+ return paramResult;
757
+ }
758
+ checkParamSchema(paramObject) {
759
+ const paramResult = {
760
+ requiredNum: 0,
761
+ optionalNum: 0,
762
+ isValid: true,
763
+ reason: [],
764
+ };
765
+ if (!paramObject) {
766
+ return paramResult;
767
+ }
768
+ const isCopilot = this.projectType === exports.ProjectType.Copilot;
769
+ for (let i = 0; i < paramObject.length; i++) {
770
+ const param = paramObject[i];
771
+ const schema = param.schema;
772
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
773
+ paramResult.isValid = false;
774
+ paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
775
+ continue;
776
+ }
777
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
778
+ if (isCopilot) {
779
+ if (isRequiredWithoutDefault) {
780
+ paramResult.requiredNum = paramResult.requiredNum + 1;
781
+ }
782
+ else {
783
+ paramResult.optionalNum = paramResult.optionalNum + 1;
784
+ }
785
+ continue;
786
+ }
787
+ if (param.in === "header" || param.in === "cookie") {
788
+ if (isRequiredWithoutDefault) {
789
+ paramResult.isValid = false;
790
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
791
+ }
792
+ continue;
793
+ }
794
+ if (schema.type !== "boolean" &&
795
+ schema.type !== "string" &&
796
+ schema.type !== "number" &&
797
+ schema.type !== "integer") {
798
+ if (isRequiredWithoutDefault) {
799
+ paramResult.isValid = false;
800
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
801
+ }
802
+ continue;
803
+ }
804
+ if (param.in === "query" || param.in === "path") {
805
+ if (isRequiredWithoutDefault) {
806
+ paramResult.requiredNum = paramResult.requiredNum + 1;
807
+ }
808
+ else {
809
+ paramResult.optionalNum = paramResult.optionalNum + 1;
870
810
  }
871
811
  }
872
812
  }
873
- return count;
813
+ return paramResult;
814
+ }
815
+ hasNestedObjectInSchema(schema) {
816
+ if (schema.type === "object") {
817
+ for (const property in schema.properties) {
818
+ const nestedSchema = schema.properties[property];
819
+ if (nestedSchema.type === "object") {
820
+ return true;
821
+ }
822
+ }
823
+ }
824
+ return false;
825
+ }
826
+ }
827
+
828
+ // Copyright (c) Microsoft Corporation.
829
+ class CopilotValidator extends Validator {
830
+ constructor(spec, options) {
831
+ super();
832
+ this.projectType = exports.ProjectType.Copilot;
833
+ this.options = options;
834
+ this.spec = spec;
835
+ }
836
+ validateSpec() {
837
+ const result = { errors: [], warnings: [] };
838
+ // validate spec version
839
+ let validationResult = this.validateSpecVersion();
840
+ result.errors.push(...validationResult.errors);
841
+ // validate spec server
842
+ validationResult = this.validateSpecServer();
843
+ result.errors.push(...validationResult.errors);
844
+ // validate no supported API
845
+ validationResult = this.validateSpecNoSupportAPI();
846
+ result.errors.push(...validationResult.errors);
847
+ // validate operationId missing
848
+ validationResult = this.validateSpecOperationId();
849
+ result.warnings.push(...validationResult.warnings);
850
+ return result;
851
+ }
852
+ validateAPI(method, path) {
853
+ const result = { isValid: true, reason: [] };
854
+ method = method.toLocaleLowerCase();
855
+ // validate method and path
856
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
857
+ if (!methodAndPathResult.isValid) {
858
+ return methodAndPathResult;
859
+ }
860
+ const operationObject = this.spec.paths[path][method];
861
+ // validate auth
862
+ const authCheckResult = this.validateAuth(method, path);
863
+ result.reason.push(...authCheckResult.reason);
864
+ // validate operationId
865
+ if (!this.options.allowMissingId && !operationObject.operationId) {
866
+ result.reason.push(exports.ErrorType.MissingOperationId);
867
+ }
868
+ // validate server
869
+ const validateServerResult = this.validateServer(method, path);
870
+ result.reason.push(...validateServerResult.reason);
871
+ // validate response
872
+ const validateResponseResult = this.validateResponse(method, path);
873
+ result.reason.push(...validateResponseResult.reason);
874
+ // validate requestBody
875
+ const requestBody = operationObject.requestBody;
876
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
877
+ if (Utils.containMultipleMediaTypes(requestBody)) {
878
+ result.reason.push(exports.ErrorType.PostBodyContainMultipleMediaTypes);
879
+ }
880
+ if (requestJsonBody) {
881
+ const requestBodySchema = requestJsonBody.schema;
882
+ if (requestBodySchema.type !== "object") {
883
+ result.reason.push(exports.ErrorType.PostBodySchemaIsNotJson);
884
+ }
885
+ const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
886
+ result.reason.push(...requestBodyParamResult.reason);
887
+ }
888
+ // validate parameters
889
+ const paramObject = operationObject.parameters;
890
+ const paramResult = this.checkParamSchema(paramObject);
891
+ result.reason.push(...paramResult.reason);
892
+ if (result.reason.length > 0) {
893
+ result.isValid = false;
894
+ }
895
+ return result;
896
+ }
897
+ }
898
+
899
+ // Copyright (c) Microsoft Corporation.
900
+ class SMEValidator extends Validator {
901
+ constructor(spec, options) {
902
+ super();
903
+ this.projectType = exports.ProjectType.SME;
904
+ this.options = options;
905
+ this.spec = spec;
906
+ }
907
+ validateSpec() {
908
+ const result = { errors: [], warnings: [] };
909
+ // validate spec version
910
+ let validationResult = this.validateSpecVersion();
911
+ result.errors.push(...validationResult.errors);
912
+ // validate spec server
913
+ validationResult = this.validateSpecServer();
914
+ result.errors.push(...validationResult.errors);
915
+ // validate no supported API
916
+ validationResult = this.validateSpecNoSupportAPI();
917
+ result.errors.push(...validationResult.errors);
918
+ // validate operationId missing
919
+ if (this.options.allowMissingId) {
920
+ validationResult = this.validateSpecOperationId();
921
+ result.warnings.push(...validationResult.warnings);
922
+ }
923
+ return result;
924
+ }
925
+ validateAPI(method, path) {
926
+ const result = { isValid: true, reason: [] };
927
+ method = method.toLocaleLowerCase();
928
+ // validate method and path
929
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
930
+ if (!methodAndPathResult.isValid) {
931
+ return methodAndPathResult;
932
+ }
933
+ const operationObject = this.spec.paths[path][method];
934
+ // validate auth
935
+ const authCheckResult = this.validateAuth(method, path);
936
+ result.reason.push(...authCheckResult.reason);
937
+ // validate operationId
938
+ if (!this.options.allowMissingId && !operationObject.operationId) {
939
+ result.reason.push(exports.ErrorType.MissingOperationId);
940
+ }
941
+ // validate server
942
+ const validateServerResult = this.validateServer(method, path);
943
+ result.reason.push(...validateServerResult.reason);
944
+ // validate response
945
+ const validateResponseResult = this.validateResponse(method, path);
946
+ result.reason.push(...validateResponseResult.reason);
947
+ let postBodyResult = {
948
+ requiredNum: 0,
949
+ optionalNum: 0,
950
+ isValid: true,
951
+ reason: [],
952
+ };
953
+ // validate requestBody
954
+ const requestBody = operationObject.requestBody;
955
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
956
+ if (Utils.containMultipleMediaTypes(requestBody)) {
957
+ result.reason.push(exports.ErrorType.PostBodyContainMultipleMediaTypes);
958
+ }
959
+ if (requestJsonBody) {
960
+ const requestBodySchema = requestJsonBody.schema;
961
+ postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
962
+ result.reason.push(...postBodyResult.reason);
963
+ }
964
+ // validate parameters
965
+ const paramObject = operationObject.parameters;
966
+ const paramResult = this.checkParamSchema(paramObject);
967
+ result.reason.push(...paramResult.reason);
968
+ // validate total parameters count
969
+ if (paramResult.isValid && postBodyResult.isValid) {
970
+ const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
971
+ result.reason.push(...paramCountResult.reason);
972
+ }
973
+ if (result.reason.length > 0) {
974
+ result.isValid = false;
975
+ }
976
+ return result;
977
+ }
978
+ validateParamCount(postBodyResult, paramResult) {
979
+ const result = { isValid: true, reason: [] };
980
+ const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
981
+ const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
982
+ if (totalRequiredParams > 1) {
983
+ if (!this.options.allowMultipleParameters ||
984
+ totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
985
+ result.reason.push(exports.ErrorType.ExceededRequiredParamsLimit);
986
+ }
987
+ }
988
+ else if (totalParams === 0) {
989
+ result.reason.push(exports.ErrorType.NoParameter);
990
+ }
991
+ return result;
992
+ }
993
+ }
994
+ SMEValidator.SMERequiredParamsMaxNum = 5;
995
+
996
+ // Copyright (c) Microsoft Corporation.
997
+ class TeamsAIValidator extends Validator {
998
+ constructor(spec, options) {
999
+ super();
1000
+ this.projectType = exports.ProjectType.TeamsAi;
1001
+ this.options = options;
1002
+ this.spec = spec;
1003
+ }
1004
+ validateSpec() {
1005
+ const result = { errors: [], warnings: [] };
1006
+ // validate spec server
1007
+ let validationResult = this.validateSpecServer();
1008
+ result.errors.push(...validationResult.errors);
1009
+ // validate no supported API
1010
+ validationResult = this.validateSpecNoSupportAPI();
1011
+ result.errors.push(...validationResult.errors);
1012
+ return result;
1013
+ }
1014
+ validateAPI(method, path) {
1015
+ const result = { isValid: true, reason: [] };
1016
+ method = method.toLocaleLowerCase();
1017
+ // validate method and path
1018
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
1019
+ if (!methodAndPathResult.isValid) {
1020
+ return methodAndPathResult;
1021
+ }
1022
+ const operationObject = this.spec.paths[path][method];
1023
+ // validate operationId
1024
+ if (!this.options.allowMissingId && !operationObject.operationId) {
1025
+ result.reason.push(exports.ErrorType.MissingOperationId);
1026
+ }
1027
+ // validate server
1028
+ const validateServerResult = this.validateServer(method, path);
1029
+ result.reason.push(...validateServerResult.reason);
1030
+ if (result.reason.length > 0) {
1031
+ result.isValid = false;
1032
+ }
1033
+ return result;
1034
+ }
1035
+ }
1036
+
1037
+ class ValidatorFactory {
1038
+ static create(spec, options) {
1039
+ var _a;
1040
+ const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : exports.ProjectType.SME;
1041
+ switch (type) {
1042
+ case exports.ProjectType.SME:
1043
+ return new SMEValidator(spec, options);
1044
+ case exports.ProjectType.Copilot:
1045
+ return new CopilotValidator(spec, options);
1046
+ case exports.ProjectType.TeamsAi:
1047
+ return new TeamsAIValidator(spec, options);
1048
+ default:
1049
+ throw new Error(`Invalid project type: ${type}`);
1050
+ }
874
1051
  }
875
1052
  }
876
1053
 
@@ -888,7 +1065,8 @@ class SpecFilter {
888
1065
  if (ConstantString.AllOperationMethods.includes(methodName) &&
889
1066
  pathObj &&
890
1067
  pathObj[methodName]) {
891
- const validateResult = Utils.isSupportedApi(methodName, path, resolvedSpec, options);
1068
+ const validator = ValidatorFactory.create(resolvedSpec, options);
1069
+ const validateResult = validator.validateAPI(methodName, path);
892
1070
  if (!validateResult.isValid) {
893
1071
  continue;
894
1072
  }
@@ -922,13 +1100,14 @@ class ManifestUpdater {
922
1100
  const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
923
1101
  manifest.plugins = [
924
1102
  {
925
- pluginFile: apiPluginRelativePath,
1103
+ file: apiPluginRelativePath,
1104
+ id: ConstantString.DefaultPluginId,
926
1105
  },
927
1106
  ];
928
1107
  const appName = this.removeEnvs(manifest.name.short);
929
1108
  ManifestUpdater.updateManifestDescription(manifest, spec);
930
1109
  const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
931
- const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
1110
+ const apiPlugin = yield ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, options);
932
1111
  return [manifest, apiPlugin];
933
1112
  });
934
1113
  }
@@ -953,88 +1132,119 @@ class ManifestUpdater {
953
1132
  }
954
1133
  return parameter;
955
1134
  }
956
- static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
957
- var _a, _b, _c;
958
- const functions = [];
959
- const functionNames = [];
960
- const paths = spec.paths;
961
- for (const pathUrl in paths) {
962
- const pathItem = paths[pathUrl];
963
- if (pathItem) {
964
- const operations = pathItem;
965
- for (const method in operations) {
966
- if (options.allowMethods.includes(method)) {
967
- const operationItem = operations[method];
968
- if (operationItem) {
969
- const operationId = operationItem.operationId;
970
- const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
971
- const paramObject = operationItem.parameters;
972
- const requestBody = operationItem.requestBody;
973
- const parameters = {
974
- type: "object",
975
- properties: {},
976
- required: [],
977
- };
978
- if (paramObject) {
979
- for (let i = 0; i < paramObject.length; i++) {
980
- const param = paramObject[i];
981
- const schema = param.schema;
982
- parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
983
- if (param.required) {
984
- parameters.required.push(param.name);
985
- }
986
- if (!parameters.properties[param.name].description) {
987
- parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
1135
+ static generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, options) {
1136
+ var _a, _b, _c, _d;
1137
+ return __awaiter(this, void 0, void 0, function* () {
1138
+ const functions = [];
1139
+ const functionNames = [];
1140
+ const paths = spec.paths;
1141
+ for (const pathUrl in paths) {
1142
+ const pathItem = paths[pathUrl];
1143
+ if (pathItem) {
1144
+ const operations = pathItem;
1145
+ for (const method in operations) {
1146
+ if (options.allowMethods.includes(method)) {
1147
+ const operationItem = operations[method];
1148
+ if (operationItem) {
1149
+ const operationId = operationItem.operationId;
1150
+ const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1151
+ const paramObject = operationItem.parameters;
1152
+ const requestBody = operationItem.requestBody;
1153
+ const parameters = {
1154
+ type: "object",
1155
+ properties: {},
1156
+ required: [],
1157
+ };
1158
+ if (paramObject) {
1159
+ for (let i = 0; i < paramObject.length; i++) {
1160
+ const param = paramObject[i];
1161
+ const schema = param.schema;
1162
+ parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
1163
+ if (param.required) {
1164
+ parameters.required.push(param.name);
1165
+ }
1166
+ if (!parameters.properties[param.name].description) {
1167
+ parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
1168
+ }
988
1169
  }
989
1170
  }
990
- }
991
- if (requestBody) {
992
- const requestJsonBody = requestBody.content["application/json"];
993
- const requestBodySchema = requestJsonBody.schema;
994
- if (requestBodySchema.type === "object") {
995
- if (requestBodySchema.required) {
996
- parameters.required.push(...requestBodySchema.required);
1171
+ if (requestBody) {
1172
+ const requestJsonBody = requestBody.content["application/json"];
1173
+ const requestBodySchema = requestJsonBody.schema;
1174
+ if (requestBodySchema.type === "object") {
1175
+ if (requestBodySchema.required) {
1176
+ parameters.required.push(...requestBodySchema.required);
1177
+ }
1178
+ for (const property in requestBodySchema.properties) {
1179
+ const schema = requestBodySchema.properties[property];
1180
+ parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
1181
+ }
997
1182
  }
998
- for (const property in requestBodySchema.properties) {
999
- const schema = requestBodySchema.properties[property];
1000
- parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
1183
+ else {
1184
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
1001
1185
  }
1002
1186
  }
1003
- else {
1004
- throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
1005
- }
1187
+ const funcObj = {
1188
+ name: operationId,
1189
+ description: description,
1190
+ parameters: parameters,
1191
+ };
1192
+ functions.push(funcObj);
1193
+ functionNames.push(operationId);
1006
1194
  }
1007
- const funcObj = {
1008
- name: operationId,
1009
- description: description,
1010
- parameters: parameters,
1011
- };
1012
- functions.push(funcObj);
1013
- functionNames.push(operationId);
1014
1195
  }
1015
1196
  }
1016
1197
  }
1017
1198
  }
1018
- }
1019
- const apiPlugin = {
1020
- schema_version: "v2",
1021
- name_for_human: appName,
1022
- description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
1023
- functions: functions,
1024
- runtimes: [
1025
- {
1199
+ let apiPlugin;
1200
+ if (yield fs__default['default'].pathExists(apiPluginFilePath)) {
1201
+ apiPlugin = yield fs__default['default'].readJSON(apiPluginFilePath);
1202
+ }
1203
+ else {
1204
+ apiPlugin = {
1205
+ schema_version: "v2",
1206
+ name_for_human: "",
1207
+ description_for_human: "",
1208
+ functions: [],
1209
+ runtimes: [],
1210
+ };
1211
+ }
1212
+ apiPlugin.functions = apiPlugin.functions || [];
1213
+ for (const func of functions) {
1214
+ const index = (_c = apiPlugin.functions) === null || _c === void 0 ? void 0 : _c.findIndex((f) => f.name === func.name);
1215
+ if (index === -1) {
1216
+ apiPlugin.functions.push(func);
1217
+ }
1218
+ else {
1219
+ apiPlugin.functions[index] = func;
1220
+ }
1221
+ }
1222
+ apiPlugin.runtimes = apiPlugin.runtimes || [];
1223
+ const index = apiPlugin.runtimes.findIndex((runtime) => runtime.spec.url === specRelativePath);
1224
+ if (index === -1) {
1225
+ apiPlugin.runtimes.push({
1026
1226
  type: "OpenApi",
1027
1227
  auth: {
1028
- type: "none", // TODO, support auth in the future
1228
+ type: "none",
1029
1229
  },
1030
1230
  spec: {
1031
1231
  url: specRelativePath,
1032
1232
  },
1033
1233
  run_for_functions: functionNames,
1034
- },
1035
- ],
1036
- };
1037
- return apiPlugin;
1234
+ });
1235
+ }
1236
+ else {
1237
+ apiPlugin.runtimes[index].run_for_functions = functionNames;
1238
+ }
1239
+ if (!apiPlugin.name_for_human) {
1240
+ apiPlugin.name_for_human = appName;
1241
+ }
1242
+ if (!apiPlugin.description_for_human) {
1243
+ apiPlugin.description_for_human =
1244
+ (_d = spec.info.description) !== null && _d !== void 0 ? _d : "<Please add description of the plugin>";
1245
+ }
1246
+ return apiPlugin;
1247
+ });
1038
1248
  }
1039
1249
  static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
1040
1250
  return __awaiter(this, void 0, void 0, function* () {
@@ -1443,6 +1653,8 @@ class SpecParser {
1443
1653
  errors: [{ type: exports.ErrorType.SpecNotValid, content: e.toString() }],
1444
1654
  };
1445
1655
  }
1656
+ const errors = [];
1657
+ const warnings = [];
1446
1658
  if (!this.options.allowSwagger && this.isSwaggerFile) {
1447
1659
  return {
1448
1660
  status: exports.ValidationStatus.Error,
@@ -1452,23 +1664,38 @@ class SpecParser {
1452
1664
  ],
1453
1665
  };
1454
1666
  }
1455
- if (this.options.projectType === exports.ProjectType.SME ||
1456
- this.options.projectType === exports.ProjectType.Copilot) {
1457
- if (this.spec.openapi >= "3.1.0") {
1458
- return {
1459
- status: exports.ValidationStatus.Error,
1460
- warnings: [],
1461
- errors: [
1462
- {
1463
- type: exports.ErrorType.SpecVersionNotSupported,
1464
- content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
1465
- data: this.spec.openapi,
1466
- },
1467
- ],
1468
- };
1469
- }
1667
+ // Remote reference not supported
1668
+ const refPaths = this.parser.$refs.paths();
1669
+ // refPaths [0] is the current spec file path
1670
+ if (refPaths.length > 1) {
1671
+ errors.push({
1672
+ type: exports.ErrorType.RemoteRefNotSupported,
1673
+ content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
1674
+ data: refPaths,
1675
+ });
1470
1676
  }
1471
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1677
+ if (!!this.isSwaggerFile && this.options.allowSwagger) {
1678
+ warnings.push({
1679
+ type: exports.WarningType.ConvertSwaggerToOpenAPI,
1680
+ content: ConstantString.ConvertSwaggerToOpenAPI,
1681
+ });
1682
+ }
1683
+ const validator = this.getValidator(this.spec);
1684
+ const validationResult = validator.validateSpec();
1685
+ warnings.push(...validationResult.warnings);
1686
+ errors.push(...validationResult.errors);
1687
+ let status = exports.ValidationStatus.Valid;
1688
+ if (warnings.length > 0 && errors.length === 0) {
1689
+ status = exports.ValidationStatus.Warning;
1690
+ }
1691
+ else if (errors.length > 0) {
1692
+ status = exports.ValidationStatus.Error;
1693
+ }
1694
+ return {
1695
+ status: status,
1696
+ warnings: warnings,
1697
+ errors: errors,
1698
+ };
1472
1699
  }
1473
1700
  catch (err) {
1474
1701
  throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
@@ -1501,34 +1728,27 @@ class SpecParser {
1501
1728
  for (const apiKey in apiMap) {
1502
1729
  const { operation, isValid, reason } = apiMap[apiKey];
1503
1730
  const [method, path] = apiKey.split(" ");
1731
+ const operationId = (_a = operation.operationId) !== null && _a !== void 0 ? _a : `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
1504
1732
  const apiResult = {
1505
- api: "",
1733
+ api: apiKey,
1506
1734
  server: "",
1507
- operationId: "",
1735
+ operationId: operationId,
1508
1736
  isValid: isValid,
1509
1737
  reason: reason,
1510
1738
  };
1511
- const rootServer = spec.servers && spec.servers[0];
1512
- const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
1513
- const operationServer = operation.servers && operation.servers[0];
1514
- const serverUrl = operationServer || methodServer || rootServer;
1515
- if (!serverUrl) {
1516
- throw new SpecParserError(ConstantString.NoServerInformation, exports.ErrorType.NoServerInformation);
1517
- }
1518
- apiResult.server = Utils.resolveEnv(serverUrl.url);
1519
- let operationId = operation.operationId;
1520
- if (!operationId) {
1521
- operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
1522
- }
1523
- apiResult.operationId = operationId;
1524
- const authArray = Utils.getAuthArray(operation.security, spec);
1525
- for (const auths of authArray) {
1526
- if (auths.length === 1) {
1527
- apiResult.auth = auths[0];
1528
- break;
1739
+ if (isValid) {
1740
+ const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
1741
+ if (serverObj) {
1742
+ apiResult.server = Utils.resolveEnv(serverObj.url);
1743
+ }
1744
+ const authArray = Utils.getAuthArray(operation.security, spec);
1745
+ for (const auths of authArray) {
1746
+ if (auths.length === 1) {
1747
+ apiResult.auth = auths[0];
1748
+ break;
1749
+ }
1529
1750
  }
1530
1751
  }
1531
- apiResult.api = apiKey;
1532
1752
  result.APIs.push(apiResult);
1533
1753
  }
1534
1754
  result.allAPICount = result.APIs.length;
@@ -1717,12 +1937,18 @@ class SpecParser {
1717
1937
  });
1718
1938
  }
1719
1939
  getAPIs(spec) {
1720
- if (this.apiMap !== undefined) {
1721
- return this.apiMap;
1940
+ const validator = this.getValidator(spec);
1941
+ const apiMap = validator.listAPIs();
1942
+ this.apiMap = apiMap;
1943
+ return apiMap;
1944
+ }
1945
+ getValidator(spec) {
1946
+ if (this.validator) {
1947
+ return this.validator;
1722
1948
  }
1723
- const result = Utils.listAPIs(spec, this.options);
1724
- this.apiMap = result;
1725
- return result;
1949
+ const validator = ValidatorFactory.create(spec, this.options);
1950
+ this.validator = validator;
1951
+ return validator;
1726
1952
  }
1727
1953
  }
1728
1954