@microsoft/m365-spec-parser 0.1.1-alpha.2f5decfcc.0 → 0.1.1-alpha.42af26ca6.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.
@@ -62,6 +62,7 @@ exports.ErrorType = void 0;
62
62
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
63
63
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
64
64
  ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
65
+ ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
65
66
  ErrorType["ListFailed"] = "list-failed";
66
67
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
67
68
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -70,6 +71,21 @@ exports.ErrorType = void 0;
70
71
  ErrorType["GenerateFailed"] = "generate-failed";
71
72
  ErrorType["ValidateFailed"] = "validate-failed";
72
73
  ErrorType["GetSpecFailed"] = "get-spec-failed";
74
+ ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
75
+ ErrorType["MissingOperationId"] = "missing-operation-id";
76
+ ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
77
+ ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
78
+ ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
79
+ ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
80
+ ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
81
+ ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
82
+ ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
83
+ ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
84
+ ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
85
+ ErrorType["NoParameter"] = "no-parameter";
86
+ ErrorType["NoAPIInfo"] = "no-api-info";
87
+ ErrorType["MethodNotAllowed"] = "method-not-allowed";
88
+ ErrorType["UrlPathNotExist"] = "url-path-not-exist";
73
89
  ErrorType["Cancelled"] = "cancelled";
74
90
  ErrorType["Unknown"] = "unknown";
75
91
  })(exports.ErrorType || (exports.ErrorType = {}));
@@ -117,6 +133,7 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
117
133
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
118
134
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
119
135
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
136
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
120
137
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
121
138
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
122
139
  ConstantString.WrappedCardVersion = "devPreview";
@@ -214,221 +231,9 @@ class Utils {
214
231
  }
215
232
  return false;
216
233
  }
217
- static checkParameters(paramObject, isCopilot) {
218
- const paramResult = {
219
- requiredNum: 0,
220
- optionalNum: 0,
221
- isValid: true,
222
- };
223
- if (!paramObject) {
224
- return paramResult;
225
- }
226
- for (let i = 0; i < paramObject.length; i++) {
227
- const param = paramObject[i];
228
- const schema = param.schema;
229
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
230
- paramResult.isValid = false;
231
- continue;
232
- }
233
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
234
- if (isCopilot) {
235
- if (isRequiredWithoutDefault) {
236
- paramResult.requiredNum = paramResult.requiredNum + 1;
237
- }
238
- else {
239
- paramResult.optionalNum = paramResult.optionalNum + 1;
240
- }
241
- continue;
242
- }
243
- if (param.in === "header" || param.in === "cookie") {
244
- if (isRequiredWithoutDefault) {
245
- paramResult.isValid = false;
246
- }
247
- continue;
248
- }
249
- if (schema.type !== "boolean" &&
250
- schema.type !== "string" &&
251
- schema.type !== "number" &&
252
- schema.type !== "integer") {
253
- if (isRequiredWithoutDefault) {
254
- paramResult.isValid = false;
255
- }
256
- continue;
257
- }
258
- if (param.in === "query" || param.in === "path") {
259
- if (isRequiredWithoutDefault) {
260
- paramResult.requiredNum = paramResult.requiredNum + 1;
261
- }
262
- else {
263
- paramResult.optionalNum = paramResult.optionalNum + 1;
264
- }
265
- }
266
- }
267
- return paramResult;
268
- }
269
- static checkPostBody(schema, isRequired = false, isCopilot = false) {
270
- var _a;
271
- const paramResult = {
272
- requiredNum: 0,
273
- optionalNum: 0,
274
- isValid: true,
275
- };
276
- if (Object.keys(schema).length === 0) {
277
- return paramResult;
278
- }
279
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
280
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
281
- paramResult.isValid = false;
282
- return paramResult;
283
- }
284
- if (schema.type === "string" ||
285
- schema.type === "integer" ||
286
- schema.type === "boolean" ||
287
- schema.type === "number") {
288
- if (isRequiredWithoutDefault) {
289
- paramResult.requiredNum = paramResult.requiredNum + 1;
290
- }
291
- else {
292
- paramResult.optionalNum = paramResult.optionalNum + 1;
293
- }
294
- }
295
- else if (schema.type === "object") {
296
- const { properties } = schema;
297
- for (const property in properties) {
298
- let isRequired = false;
299
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
300
- isRequired = true;
301
- }
302
- const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
303
- paramResult.requiredNum += result.requiredNum;
304
- paramResult.optionalNum += result.optionalNum;
305
- paramResult.isValid = paramResult.isValid && result.isValid;
306
- }
307
- }
308
- else {
309
- if (isRequiredWithoutDefault && !isCopilot) {
310
- paramResult.isValid = false;
311
- }
312
- }
313
- return paramResult;
314
- }
315
234
  static containMultipleMediaTypes(bodyObject) {
316
235
  return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
317
236
  }
318
- /**
319
- * Checks if the given API is supported.
320
- * @param {string} method - The HTTP method of the API.
321
- * @param {string} path - The path of the API.
322
- * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
323
- * @returns {boolean} - Returns true if the API is supported, false otherwise.
324
- * @description The following APIs are supported:
325
- * 1. only support Get/Post operation without auth property
326
- * 2. parameter inside query or path only support string, number, boolean and integer
327
- * 3. parameter inside post body only support string, number, boolean, integer and object
328
- * 4. request body + required parameters <= 1
329
- * 5. response body should be “application/json” and not empty, and response code should be 20X
330
- * 6. only support request body with “application/json” content type
331
- */
332
- static isSupportedApi(method, path, spec, options) {
333
- var _a;
334
- const pathObj = spec.paths[path];
335
- method = method.toLocaleLowerCase();
336
- if (pathObj) {
337
- if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
338
- const securities = pathObj[method].security;
339
- const isTeamsAi = options.projectType === exports.ProjectType.TeamsAi;
340
- const isCopilot = options.projectType === exports.ProjectType.Copilot;
341
- // Teams AI project doesn't care about auth, it will use authProvider for user to implement
342
- if (!isTeamsAi) {
343
- const authArray = Utils.getAuthArray(securities, spec);
344
- if (!Utils.isSupportedAuth(authArray, options)) {
345
- return false;
346
- }
347
- }
348
- const operationObject = pathObj[method];
349
- if (!options.allowMissingId && !operationObject.operationId) {
350
- return false;
351
- }
352
- const paramObject = operationObject.parameters;
353
- const requestBody = operationObject.requestBody;
354
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
355
- if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
356
- return false;
357
- }
358
- const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
359
- if (Object.keys(responseJson).length === 0) {
360
- return false;
361
- }
362
- // Teams AI project doesn't care about request parameters/body
363
- if (isTeamsAi) {
364
- return true;
365
- }
366
- let requestBodyParamResult = {
367
- requiredNum: 0,
368
- optionalNum: 0,
369
- isValid: true,
370
- };
371
- if (requestJsonBody) {
372
- const requestBodySchema = requestJsonBody.schema;
373
- if (isCopilot && requestBodySchema.type !== "object") {
374
- return false;
375
- }
376
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
377
- }
378
- if (!requestBodyParamResult.isValid) {
379
- return false;
380
- }
381
- const paramResult = Utils.checkParameters(paramObject, isCopilot);
382
- if (!paramResult.isValid) {
383
- return false;
384
- }
385
- // Copilot support arbitrary parameters
386
- if (isCopilot) {
387
- return true;
388
- }
389
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
390
- if (options.allowMultipleParameters &&
391
- requestBodyParamResult.requiredNum + paramResult.requiredNum <=
392
- ConstantString.SMERequiredParamsMaxNum) {
393
- return true;
394
- }
395
- return false;
396
- }
397
- else if (requestBodyParamResult.requiredNum +
398
- requestBodyParamResult.optionalNum +
399
- paramResult.requiredNum +
400
- paramResult.optionalNum ===
401
- 0) {
402
- return false;
403
- }
404
- else {
405
- return true;
406
- }
407
- }
408
- }
409
- return false;
410
- }
411
- static isSupportedAuth(authSchemeArray, options) {
412
- if (authSchemeArray.length === 0) {
413
- return true;
414
- }
415
- if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
416
- // Currently we don't support multiple auth in one operation
417
- if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
418
- return false;
419
- }
420
- for (const auths of authSchemeArray) {
421
- if (auths.length === 1) {
422
- if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
423
- (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
424
- (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
425
- return true;
426
- }
427
- }
428
- }
429
- }
430
- return false;
431
- }
432
237
  static isBearerTokenAuth(authScheme) {
433
238
  return authScheme.type === "http" && authScheme.scheme === "bearer";
434
239
  }
@@ -436,10 +241,9 @@ class Utils {
436
241
  return authScheme.type === "apiKey";
437
242
  }
438
243
  static isOAuthWithAuthCodeFlow(authScheme) {
439
- if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
440
- return true;
441
- }
442
- return false;
244
+ return !!(authScheme.type === "oauth2" &&
245
+ authScheme.flows &&
246
+ authScheme.flows.authorizationCode);
443
247
  }
444
248
  static getAuthArray(securities, spec) {
445
249
  var _a;
@@ -467,14 +271,17 @@ class Utils {
467
271
  static updateFirstLetter(str) {
468
272
  return str.charAt(0).toUpperCase() + str.slice(1);
469
273
  }
470
- static getResponseJson(operationObject, isTeamsAiProject = false) {
274
+ static getResponseJson(operationObject) {
471
275
  var _a, _b;
472
276
  let json = {};
277
+ let multipleMediaType = false;
473
278
  for (const code of ConstantString.ResponseCodeFor20X) {
474
279
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
475
280
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
281
+ multipleMediaType = false;
476
282
  json = responseObject.content["application/json"];
477
- if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
283
+ if (Utils.containMultipleMediaTypes(responseObject)) {
284
+ multipleMediaType = true;
478
285
  json = {};
479
286
  }
480
287
  else {
@@ -482,7 +289,7 @@ class Utils {
482
289
  }
483
290
  }
484
291
  }
485
- return json;
292
+ return { json, multipleMediaType };
486
293
  }
487
294
  static convertPathToCamelCase(path) {
488
295
  const pathSegments = path.split(/[./{]/);
@@ -502,10 +309,10 @@ class Utils {
502
309
  return undefined;
503
310
  }
504
311
  }
505
- static resolveServerUrl(url) {
312
+ static resolveEnv(str) {
506
313
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
507
- let matches = placeHolderReg.exec(url);
508
- let newUrl = url;
314
+ let matches = placeHolderReg.exec(str);
315
+ let newStr = str;
509
316
  while (matches != null) {
510
317
  const envVar = matches[1];
511
318
  const envVal = process.env[envVar];
@@ -513,17 +320,17 @@ class Utils {
513
320
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
514
321
  }
515
322
  else {
516
- newUrl = newUrl.replace(matches[0], envVal);
323
+ newStr = newStr.replace(matches[0], envVal);
517
324
  }
518
- matches = placeHolderReg.exec(url);
325
+ matches = placeHolderReg.exec(str);
519
326
  }
520
- return newUrl;
327
+ return newStr;
521
328
  }
522
329
  static checkServerUrl(servers) {
523
330
  const errors = [];
524
331
  let serverUrl;
525
332
  try {
526
- serverUrl = Utils.resolveServerUrl(servers[0].url);
333
+ serverUrl = Utils.resolveEnv(servers[0].url);
527
334
  }
528
335
  catch (err) {
529
336
  errors.push({
@@ -554,6 +361,7 @@ class Utils {
554
361
  return errors;
555
362
  }
556
363
  static validateServer(spec, options) {
364
+ var _a;
557
365
  const errors = [];
558
366
  let hasTopLevelServers = false;
559
367
  let hasPathLevelServers = false;
@@ -574,7 +382,7 @@ class Utils {
574
382
  }
575
383
  for (const method in methods) {
576
384
  const operationObject = methods[method];
577
- if (Utils.isSupportedApi(method, path, spec, options)) {
385
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
578
386
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
579
387
  hasOperationLevelServers = true;
580
388
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -701,13 +509,7 @@ class Utils {
701
509
  }
702
510
  }
703
511
  const operationId = operationItem.operationId;
704
- const parameters = [];
705
- if (requiredParams.length !== 0) {
706
- parameters.push(...requiredParams);
707
- }
708
- else {
709
- parameters.push(optionalParams[0]);
710
- }
512
+ const parameters = [...requiredParams, ...optionalParams];
711
513
  const command = {
712
514
  context: ["compose"],
713
515
  type: "query",
@@ -716,142 +518,559 @@ class Utils {
716
518
  parameters: parameters,
717
519
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
718
520
  };
719
- let warning = undefined;
720
- if (requiredParams.length === 0 && optionalParams.length > 1) {
721
- warning = {
722
- type: exports.WarningType.OperationOnlyContainsOptionalParam,
723
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
724
- data: operationId,
725
- };
521
+ return command;
522
+ }
523
+ static format(str, ...args) {
524
+ let index = 0;
525
+ return str.replace(/%s/g, () => {
526
+ const arg = args[index++];
527
+ return arg !== undefined ? arg : "";
528
+ });
529
+ }
530
+ static getSafeRegistrationIdEnvName(authName) {
531
+ if (!authName) {
532
+ return "";
726
533
  }
727
- return [command, warning];
534
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
535
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
536
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
537
+ }
538
+ return safeRegistrationIdEnvName;
728
539
  }
729
- static listSupportedAPIs(spec, options) {
730
- const paths = spec.paths;
540
+ static getServerObject(spec, method, path) {
541
+ const pathObj = spec.paths[path];
542
+ const operationObject = pathObj[method];
543
+ const rootServer = spec.servers && spec.servers[0];
544
+ const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
545
+ const operationServer = operationObject.servers && operationObject.servers[0];
546
+ const serverUrl = operationServer || methodServer || rootServer;
547
+ return serverUrl;
548
+ }
549
+ }
550
+
551
+ // Copyright (c) Microsoft Corporation.
552
+ class Validator {
553
+ listAPIs() {
554
+ var _a;
555
+ if (this.apiMap) {
556
+ return this.apiMap;
557
+ }
558
+ const paths = this.spec.paths;
731
559
  const result = {};
732
560
  for (const path in paths) {
733
561
  const methods = paths[path];
734
562
  for (const method in methods) {
735
- if (Utils.isSupportedApi(method, path, spec, options)) {
736
- const operationObject = methods[method];
737
- result[`${method.toUpperCase()} ${path}`] = operationObject;
563
+ const operationObject = methods[method];
564
+ if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
565
+ const validateResult = this.validateAPI(method, path);
566
+ result[`${method.toUpperCase()} ${path}`] = {
567
+ operation: operationObject,
568
+ isValid: validateResult.isValid,
569
+ reason: validateResult.reason,
570
+ };
738
571
  }
739
572
  }
740
573
  }
574
+ this.apiMap = result;
741
575
  return result;
742
576
  }
743
- static validateSpec(spec, parser, isSwaggerFile, options) {
744
- const errors = [];
745
- const warnings = [];
746
- if (isSwaggerFile) {
747
- warnings.push({
748
- type: exports.WarningType.ConvertSwaggerToOpenAPI,
749
- content: ConstantString.ConvertSwaggerToOpenAPI,
750
- });
751
- }
752
- // Server validation
753
- const serverErrors = Utils.validateServer(spec, options);
754
- errors.push(...serverErrors);
755
- // Remote reference not supported
756
- const refPaths = parser.$refs.paths();
757
- // refPaths [0] is the current spec file path
758
- if (refPaths.length > 1) {
759
- errors.push({
760
- type: exports.ErrorType.RemoteRefNotSupported,
761
- content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
762
- data: refPaths,
577
+ validateSpecVersion() {
578
+ const result = { errors: [], warnings: [] };
579
+ if (this.spec.openapi >= "3.1.0") {
580
+ result.errors.push({
581
+ type: exports.ErrorType.SpecVersionNotSupported,
582
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
583
+ data: this.spec.openapi,
763
584
  });
764
585
  }
765
- // No supported API
766
- const apiMap = Utils.listSupportedAPIs(spec, options);
767
- if (Object.keys(apiMap).length === 0) {
768
- errors.push({
586
+ return result;
587
+ }
588
+ validateSpecServer() {
589
+ const result = { errors: [], warnings: [] };
590
+ const serverErrors = Utils.validateServer(this.spec, this.options);
591
+ result.errors.push(...serverErrors);
592
+ return result;
593
+ }
594
+ validateSpecNoSupportAPI() {
595
+ const result = { errors: [], warnings: [] };
596
+ const apiMap = this.listAPIs();
597
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
598
+ if (validAPIs.length === 0) {
599
+ result.errors.push({
769
600
  type: exports.ErrorType.NoSupportedApi,
770
601
  content: ConstantString.NoSupportedApi,
771
602
  });
772
603
  }
604
+ return result;
605
+ }
606
+ validateSpecOperationId() {
607
+ const result = { errors: [], warnings: [] };
608
+ const apiMap = this.listAPIs();
773
609
  // OperationId missing
774
610
  const apisMissingOperationId = [];
775
611
  for (const key in apiMap) {
776
- const pathObjectItem = apiMap[key];
777
- if (!pathObjectItem.operationId) {
612
+ const { operation } = apiMap[key];
613
+ if (!operation.operationId) {
778
614
  apisMissingOperationId.push(key);
779
615
  }
780
616
  }
781
617
  if (apisMissingOperationId.length > 0) {
782
- warnings.push({
618
+ result.warnings.push({
783
619
  type: exports.WarningType.OperationIdMissing,
784
620
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
785
621
  data: apisMissingOperationId,
786
622
  });
787
623
  }
788
- let status = exports.ValidationStatus.Valid;
789
- if (warnings.length > 0 && errors.length === 0) {
790
- status = exports.ValidationStatus.Warning;
624
+ return result;
625
+ }
626
+ validateMethodAndPath(method, path) {
627
+ const result = { isValid: true, reason: [] };
628
+ if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
629
+ result.isValid = false;
630
+ result.reason.push(exports.ErrorType.MethodNotAllowed);
631
+ return result;
791
632
  }
792
- else if (errors.length > 0) {
793
- status = exports.ValidationStatus.Error;
633
+ const pathObj = this.spec.paths[path];
634
+ if (!pathObj || !pathObj[method]) {
635
+ result.isValid = false;
636
+ result.reason.push(exports.ErrorType.UrlPathNotExist);
637
+ return result;
794
638
  }
795
- return {
796
- status,
797
- warnings,
798
- errors,
799
- };
639
+ return result;
800
640
  }
801
- static format(str, ...args) {
802
- let index = 0;
803
- return str.replace(/%s/g, () => {
804
- const arg = args[index++];
805
- return arg !== undefined ? arg : "";
806
- });
641
+ validateResponse(method, path) {
642
+ const result = { isValid: true, reason: [] };
643
+ const operationObject = this.spec.paths[path][method];
644
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
645
+ // only support response body only contains “application/json” content type
646
+ if (multipleMediaType) {
647
+ result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
648
+ }
649
+ else if (Object.keys(json).length === 0) {
650
+ // response body should not be empty
651
+ result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
652
+ }
653
+ return result;
807
654
  }
808
- static getSafeRegistrationIdEnvName(authName) {
809
- if (!authName) {
810
- return "";
655
+ validateServer(method, path) {
656
+ const result = { isValid: true, reason: [] };
657
+ const serverObj = Utils.getServerObject(this.spec, method, path);
658
+ if (!serverObj) {
659
+ // should contain server URL
660
+ result.reason.push(exports.ErrorType.NoServerInformation);
811
661
  }
812
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
813
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
814
- safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
662
+ else {
663
+ // server url should be absolute url with https protocol
664
+ const serverValidateResult = Utils.checkServerUrl([serverObj]);
665
+ result.reason.push(...serverValidateResult.map((item) => item.type));
815
666
  }
816
- return safeRegistrationIdEnvName;
667
+ return result;
817
668
  }
818
- static getAllAPICount(spec) {
819
- let count = 0;
820
- const paths = spec.paths;
821
- for (const path in paths) {
822
- const methods = paths[path];
823
- for (const method in methods) {
824
- if (ConstantString.AllOperationMethods.includes(method)) {
825
- count++;
669
+ validateAuth(method, path) {
670
+ const pathObj = this.spec.paths[path];
671
+ const operationObject = pathObj[method];
672
+ const securities = operationObject.security;
673
+ const authSchemeArray = Utils.getAuthArray(securities, this.spec);
674
+ if (authSchemeArray.length === 0) {
675
+ return { isValid: true, reason: [] };
676
+ }
677
+ if (this.options.allowAPIKeyAuth ||
678
+ this.options.allowOauth2 ||
679
+ this.options.allowBearerTokenAuth) {
680
+ // Currently we don't support multiple auth in one operation
681
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
682
+ return {
683
+ isValid: false,
684
+ reason: [exports.ErrorType.MultipleAuthNotSupported],
685
+ };
686
+ }
687
+ for (const auths of authSchemeArray) {
688
+ if (auths.length === 1) {
689
+ if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
690
+ (this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
691
+ (this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
692
+ return { isValid: true, reason: [] };
693
+ }
694
+ }
695
+ }
696
+ }
697
+ return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
698
+ }
699
+ checkPostBodySchema(schema, isRequired = false) {
700
+ var _a;
701
+ const paramResult = {
702
+ requiredNum: 0,
703
+ optionalNum: 0,
704
+ isValid: true,
705
+ reason: [],
706
+ };
707
+ if (Object.keys(schema).length === 0) {
708
+ return paramResult;
709
+ }
710
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
711
+ const isCopilot = this.projectType === exports.ProjectType.Copilot;
712
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
713
+ paramResult.isValid = false;
714
+ paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
715
+ return paramResult;
716
+ }
717
+ if (schema.type === "string" ||
718
+ schema.type === "integer" ||
719
+ schema.type === "boolean" ||
720
+ schema.type === "number") {
721
+ if (isRequiredWithoutDefault) {
722
+ paramResult.requiredNum = paramResult.requiredNum + 1;
723
+ }
724
+ else {
725
+ paramResult.optionalNum = paramResult.optionalNum + 1;
726
+ }
727
+ }
728
+ else if (schema.type === "object") {
729
+ const { properties } = schema;
730
+ for (const property in properties) {
731
+ let isRequired = false;
732
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
733
+ isRequired = true;
826
734
  }
735
+ const result = this.checkPostBodySchema(properties[property], isRequired);
736
+ paramResult.requiredNum += result.requiredNum;
737
+ paramResult.optionalNum += result.optionalNum;
738
+ paramResult.isValid = paramResult.isValid && result.isValid;
739
+ paramResult.reason.push(...result.reason);
827
740
  }
828
741
  }
829
- return count;
742
+ else {
743
+ if (isRequiredWithoutDefault && !isCopilot) {
744
+ paramResult.isValid = false;
745
+ paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
746
+ }
747
+ }
748
+ return paramResult;
749
+ }
750
+ checkParamSchema(paramObject) {
751
+ const paramResult = {
752
+ requiredNum: 0,
753
+ optionalNum: 0,
754
+ isValid: true,
755
+ reason: [],
756
+ };
757
+ if (!paramObject) {
758
+ return paramResult;
759
+ }
760
+ const isCopilot = this.projectType === exports.ProjectType.Copilot;
761
+ for (let i = 0; i < paramObject.length; i++) {
762
+ const param = paramObject[i];
763
+ const schema = param.schema;
764
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
765
+ paramResult.isValid = false;
766
+ paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
767
+ continue;
768
+ }
769
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
770
+ if (isCopilot) {
771
+ if (isRequiredWithoutDefault) {
772
+ paramResult.requiredNum = paramResult.requiredNum + 1;
773
+ }
774
+ else {
775
+ paramResult.optionalNum = paramResult.optionalNum + 1;
776
+ }
777
+ continue;
778
+ }
779
+ if (param.in === "header" || param.in === "cookie") {
780
+ if (isRequiredWithoutDefault) {
781
+ paramResult.isValid = false;
782
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
783
+ }
784
+ continue;
785
+ }
786
+ if (schema.type !== "boolean" &&
787
+ schema.type !== "string" &&
788
+ schema.type !== "number" &&
789
+ schema.type !== "integer") {
790
+ if (isRequiredWithoutDefault) {
791
+ paramResult.isValid = false;
792
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
793
+ }
794
+ continue;
795
+ }
796
+ if (param.in === "query" || param.in === "path") {
797
+ if (isRequiredWithoutDefault) {
798
+ paramResult.requiredNum = paramResult.requiredNum + 1;
799
+ }
800
+ else {
801
+ paramResult.optionalNum = paramResult.optionalNum + 1;
802
+ }
803
+ }
804
+ }
805
+ return paramResult;
806
+ }
807
+ hasNestedObjectInSchema(schema) {
808
+ if (schema.type === "object") {
809
+ for (const property in schema.properties) {
810
+ const nestedSchema = schema.properties[property];
811
+ if (nestedSchema.type === "object") {
812
+ return true;
813
+ }
814
+ }
815
+ }
816
+ return false;
817
+ }
818
+ }
819
+
820
+ // Copyright (c) Microsoft Corporation.
821
+ class CopilotValidator extends Validator {
822
+ constructor(spec, options) {
823
+ super();
824
+ this.projectType = exports.ProjectType.Copilot;
825
+ this.options = options;
826
+ this.spec = spec;
827
+ }
828
+ validateSpec() {
829
+ const result = { errors: [], warnings: [] };
830
+ // validate spec version
831
+ let validationResult = this.validateSpecVersion();
832
+ result.errors.push(...validationResult.errors);
833
+ // validate spec server
834
+ validationResult = this.validateSpecServer();
835
+ result.errors.push(...validationResult.errors);
836
+ // validate no supported API
837
+ validationResult = this.validateSpecNoSupportAPI();
838
+ result.errors.push(...validationResult.errors);
839
+ // validate operationId missing
840
+ validationResult = this.validateSpecOperationId();
841
+ result.warnings.push(...validationResult.warnings);
842
+ return result;
843
+ }
844
+ validateAPI(method, path) {
845
+ const result = { isValid: true, reason: [] };
846
+ method = method.toLocaleLowerCase();
847
+ // validate method and path
848
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
849
+ if (!methodAndPathResult.isValid) {
850
+ return methodAndPathResult;
851
+ }
852
+ const operationObject = this.spec.paths[path][method];
853
+ // validate auth
854
+ const authCheckResult = this.validateAuth(method, path);
855
+ result.reason.push(...authCheckResult.reason);
856
+ // validate operationId
857
+ if (!this.options.allowMissingId && !operationObject.operationId) {
858
+ result.reason.push(exports.ErrorType.MissingOperationId);
859
+ }
860
+ // validate server
861
+ const validateServerResult = this.validateServer(method, path);
862
+ result.reason.push(...validateServerResult.reason);
863
+ // validate response
864
+ const validateResponseResult = this.validateResponse(method, path);
865
+ result.reason.push(...validateResponseResult.reason);
866
+ // validate requestBody
867
+ const requestBody = operationObject.requestBody;
868
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
869
+ if (Utils.containMultipleMediaTypes(requestBody)) {
870
+ result.reason.push(exports.ErrorType.PostBodyContainMultipleMediaTypes);
871
+ }
872
+ if (requestJsonBody) {
873
+ const requestBodySchema = requestJsonBody.schema;
874
+ if (requestBodySchema.type !== "object") {
875
+ result.reason.push(exports.ErrorType.PostBodySchemaIsNotJson);
876
+ }
877
+ const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
878
+ result.reason.push(...requestBodyParamResult.reason);
879
+ }
880
+ // validate parameters
881
+ const paramObject = operationObject.parameters;
882
+ const paramResult = this.checkParamSchema(paramObject);
883
+ result.reason.push(...paramResult.reason);
884
+ if (result.reason.length > 0) {
885
+ result.isValid = false;
886
+ }
887
+ return result;
888
+ }
889
+ }
890
+
891
+ // Copyright (c) Microsoft Corporation.
892
+ class SMEValidator extends Validator {
893
+ constructor(spec, options) {
894
+ super();
895
+ this.projectType = exports.ProjectType.SME;
896
+ this.options = options;
897
+ this.spec = spec;
898
+ }
899
+ validateSpec() {
900
+ const result = { errors: [], warnings: [] };
901
+ // validate spec version
902
+ let validationResult = this.validateSpecVersion();
903
+ result.errors.push(...validationResult.errors);
904
+ // validate spec server
905
+ validationResult = this.validateSpecServer();
906
+ result.errors.push(...validationResult.errors);
907
+ // validate no supported API
908
+ validationResult = this.validateSpecNoSupportAPI();
909
+ result.errors.push(...validationResult.errors);
910
+ // validate operationId missing
911
+ validationResult = this.validateSpecOperationId();
912
+ result.warnings.push(...validationResult.warnings);
913
+ return result;
914
+ }
915
+ validateAPI(method, path) {
916
+ const result = { isValid: true, reason: [] };
917
+ method = method.toLocaleLowerCase();
918
+ // validate method and path
919
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
920
+ if (!methodAndPathResult.isValid) {
921
+ return methodAndPathResult;
922
+ }
923
+ const operationObject = this.spec.paths[path][method];
924
+ // validate auth
925
+ const authCheckResult = this.validateAuth(method, path);
926
+ result.reason.push(...authCheckResult.reason);
927
+ // validate operationId
928
+ if (!this.options.allowMissingId && !operationObject.operationId) {
929
+ result.reason.push(exports.ErrorType.MissingOperationId);
930
+ }
931
+ // validate server
932
+ const validateServerResult = this.validateServer(method, path);
933
+ result.reason.push(...validateServerResult.reason);
934
+ // validate response
935
+ const validateResponseResult = this.validateResponse(method, path);
936
+ result.reason.push(...validateResponseResult.reason);
937
+ let postBodyResult = {
938
+ requiredNum: 0,
939
+ optionalNum: 0,
940
+ isValid: true,
941
+ reason: [],
942
+ };
943
+ // validate requestBody
944
+ const requestBody = operationObject.requestBody;
945
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
946
+ if (Utils.containMultipleMediaTypes(requestBody)) {
947
+ result.reason.push(exports.ErrorType.PostBodyContainMultipleMediaTypes);
948
+ }
949
+ if (requestJsonBody) {
950
+ const requestBodySchema = requestJsonBody.schema;
951
+ postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
952
+ result.reason.push(...postBodyResult.reason);
953
+ }
954
+ // validate parameters
955
+ const paramObject = operationObject.parameters;
956
+ const paramResult = this.checkParamSchema(paramObject);
957
+ result.reason.push(...paramResult.reason);
958
+ // validate total parameters count
959
+ if (paramResult.isValid && postBodyResult.isValid) {
960
+ const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
961
+ result.reason.push(...paramCountResult.reason);
962
+ }
963
+ if (result.reason.length > 0) {
964
+ result.isValid = false;
965
+ }
966
+ return result;
967
+ }
968
+ validateParamCount(postBodyResult, paramResult) {
969
+ const result = { isValid: true, reason: [] };
970
+ const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
971
+ const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
972
+ if (totalRequiredParams > 1) {
973
+ if (!this.options.allowMultipleParameters ||
974
+ totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
975
+ result.reason.push(exports.ErrorType.ExceededRequiredParamsLimit);
976
+ }
977
+ }
978
+ else if (totalParams === 0) {
979
+ result.reason.push(exports.ErrorType.NoParameter);
980
+ }
981
+ return result;
982
+ }
983
+ }
984
+ SMEValidator.SMERequiredParamsMaxNum = 5;
985
+
986
+ // Copyright (c) Microsoft Corporation.
987
+ class TeamsAIValidator extends Validator {
988
+ constructor(spec, options) {
989
+ super();
990
+ this.projectType = exports.ProjectType.TeamsAi;
991
+ this.options = options;
992
+ this.spec = spec;
993
+ }
994
+ validateSpec() {
995
+ const result = { errors: [], warnings: [] };
996
+ // validate spec server
997
+ let validationResult = this.validateSpecServer();
998
+ result.errors.push(...validationResult.errors);
999
+ // validate no supported API
1000
+ validationResult = this.validateSpecNoSupportAPI();
1001
+ result.errors.push(...validationResult.errors);
1002
+ return result;
1003
+ }
1004
+ validateAPI(method, path) {
1005
+ const result = { isValid: true, reason: [] };
1006
+ method = method.toLocaleLowerCase();
1007
+ // validate method and path
1008
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
1009
+ if (!methodAndPathResult.isValid) {
1010
+ return methodAndPathResult;
1011
+ }
1012
+ const operationObject = this.spec.paths[path][method];
1013
+ // validate operationId
1014
+ if (!this.options.allowMissingId && !operationObject.operationId) {
1015
+ result.reason.push(exports.ErrorType.MissingOperationId);
1016
+ }
1017
+ // validate server
1018
+ const validateServerResult = this.validateServer(method, path);
1019
+ result.reason.push(...validateServerResult.reason);
1020
+ if (result.reason.length > 0) {
1021
+ result.isValid = false;
1022
+ }
1023
+ return result;
1024
+ }
1025
+ }
1026
+
1027
+ class ValidatorFactory {
1028
+ static create(spec, options) {
1029
+ var _a;
1030
+ const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : exports.ProjectType.SME;
1031
+ switch (type) {
1032
+ case exports.ProjectType.SME:
1033
+ return new SMEValidator(spec, options);
1034
+ case exports.ProjectType.Copilot:
1035
+ return new CopilotValidator(spec, options);
1036
+ case exports.ProjectType.TeamsAi:
1037
+ return new TeamsAIValidator(spec, options);
1038
+ default:
1039
+ throw new Error(`Invalid project type: ${type}`);
1040
+ }
830
1041
  }
831
1042
  }
832
1043
 
833
1044
  // Copyright (c) Microsoft Corporation.
834
1045
  class SpecFilter {
835
1046
  static specFilter(filter, unResolveSpec, resolvedSpec, options) {
1047
+ var _a;
836
1048
  try {
837
1049
  const newSpec = Object.assign({}, unResolveSpec);
838
1050
  const newPaths = {};
839
1051
  for (const filterItem of filter) {
840
1052
  const [method, path] = filterItem.split(" ");
841
1053
  const methodName = method.toLowerCase();
842
- if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
843
- continue;
844
- }
845
- if (!newPaths[path]) {
846
- newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
847
- for (const m of ConstantString.AllOperationMethods) {
848
- delete newPaths[path][m];
1054
+ const pathObj = (_a = resolvedSpec.paths) === null || _a === void 0 ? void 0 : _a[path];
1055
+ if (ConstantString.AllOperationMethods.includes(methodName) &&
1056
+ pathObj &&
1057
+ pathObj[methodName]) {
1058
+ const validator = ValidatorFactory.create(resolvedSpec, options);
1059
+ const validateResult = validator.validateAPI(methodName, path);
1060
+ if (!validateResult.isValid) {
1061
+ continue;
1062
+ }
1063
+ if (!newPaths[path]) {
1064
+ newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
1065
+ for (const m of ConstantString.AllOperationMethods) {
1066
+ delete newPaths[path][m];
1067
+ }
1068
+ }
1069
+ newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
1070
+ // Add the operationId if missing
1071
+ if (!newPaths[path][methodName].operationId) {
1072
+ newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
849
1073
  }
850
- }
851
- newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
852
- // Add the operationId if missing
853
- if (!newPaths[path][methodName].operationId) {
854
- newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
855
1074
  }
856
1075
  }
857
1076
  newSpec.paths = newPaths;
@@ -874,9 +1093,10 @@ class ManifestUpdater {
874
1093
  pluginFile: apiPluginRelativePath,
875
1094
  },
876
1095
  ];
1096
+ const appName = this.removeEnvs(manifest.name.short);
877
1097
  ManifestUpdater.updateManifestDescription(manifest, spec);
878
1098
  const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
879
- const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
1099
+ const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
880
1100
  return [manifest, apiPlugin];
881
1101
  });
882
1102
  }
@@ -901,7 +1121,7 @@ class ManifestUpdater {
901
1121
  }
902
1122
  return parameter;
903
1123
  }
904
- static generatePluginManifestSchema(spec, specRelativePath, options) {
1124
+ static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
905
1125
  var _a, _b, _c;
906
1126
  const functions = [];
907
1127
  const functionNames = [];
@@ -966,7 +1186,7 @@ class ManifestUpdater {
966
1186
  }
967
1187
  const apiPlugin = {
968
1188
  schema_version: "v2",
969
- name_for_human: spec.info.title,
1189
+ name_for_human: appName,
970
1190
  description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
971
1191
  functions: functions,
972
1192
  runtimes: [
@@ -1053,16 +1273,26 @@ class ManifestUpdater {
1053
1273
  if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
1054
1274
  const operationItem = operations[method];
1055
1275
  if (operationItem) {
1056
- const [command, warning] = Utils.parseApiInfo(operationItem, options);
1276
+ const command = Utils.parseApiInfo(operationItem, options);
1277
+ if (command.parameters &&
1278
+ command.parameters.length >= 1 &&
1279
+ command.parameters.some((param) => param.isRequired)) {
1280
+ command.parameters = command.parameters.filter((param) => param.isRequired);
1281
+ }
1282
+ else if (command.parameters && command.parameters.length > 0) {
1283
+ command.parameters = [command.parameters[0]];
1284
+ warnings.push({
1285
+ type: exports.WarningType.OperationOnlyContainsOptionalParam,
1286
+ content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
1287
+ data: command.id,
1288
+ });
1289
+ }
1057
1290
  if (adaptiveCardFolder) {
1058
1291
  const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
1059
1292
  command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
1060
1293
  ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
1061
1294
  : "";
1062
1295
  }
1063
- if (warning) {
1064
- warnings.push(warning);
1065
- }
1066
1296
  commands.push(command);
1067
1297
  }
1068
1298
  }
@@ -1077,13 +1307,22 @@ class ManifestUpdater {
1077
1307
  const relativePath = path__default['default'].relative(path__default['default'].dirname(from), to);
1078
1308
  return path__default['default'].normalize(relativePath).replace(/\\/g, "/");
1079
1309
  }
1310
+ static removeEnvs(str) {
1311
+ const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
1312
+ const matches = placeHolderReg.exec(str);
1313
+ let newStr = str;
1314
+ if (matches != null) {
1315
+ newStr = newStr.replace(matches[0], "");
1316
+ }
1317
+ return newStr;
1318
+ }
1080
1319
  }
1081
1320
 
1082
1321
  // Copyright (c) Microsoft Corporation.
1083
1322
  class AdaptiveCardGenerator {
1084
1323
  static generateAdaptiveCard(operationItem) {
1085
1324
  try {
1086
- const json = Utils.getResponseJson(operationItem);
1325
+ const { json } = Utils.getResponseJson(operationItem);
1087
1326
  let cardBody = [];
1088
1327
  let schema = json.schema;
1089
1328
  let jsonPath = "$";
@@ -1372,6 +1611,8 @@ class SpecParser {
1372
1611
  errors: [{ type: exports.ErrorType.SpecNotValid, content: e.toString() }],
1373
1612
  };
1374
1613
  }
1614
+ const errors = [];
1615
+ const warnings = [];
1375
1616
  if (!this.options.allowSwagger && this.isSwaggerFile) {
1376
1617
  return {
1377
1618
  status: exports.ValidationStatus.Error,
@@ -1381,7 +1622,38 @@ class SpecParser {
1381
1622
  ],
1382
1623
  };
1383
1624
  }
1384
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1625
+ // Remote reference not supported
1626
+ const refPaths = this.parser.$refs.paths();
1627
+ // refPaths [0] is the current spec file path
1628
+ if (refPaths.length > 1) {
1629
+ errors.push({
1630
+ type: exports.ErrorType.RemoteRefNotSupported,
1631
+ content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
1632
+ data: refPaths,
1633
+ });
1634
+ }
1635
+ if (!!this.isSwaggerFile && this.options.allowSwagger) {
1636
+ warnings.push({
1637
+ type: exports.WarningType.ConvertSwaggerToOpenAPI,
1638
+ content: ConstantString.ConvertSwaggerToOpenAPI,
1639
+ });
1640
+ }
1641
+ const validator = this.getValidator(this.spec);
1642
+ const validationResult = validator.validateSpec();
1643
+ warnings.push(...validationResult.warnings);
1644
+ errors.push(...validationResult.errors);
1645
+ let status = exports.ValidationStatus.Valid;
1646
+ if (warnings.length > 0 && errors.length === 0) {
1647
+ status = exports.ValidationStatus.Warning;
1648
+ }
1649
+ else if (errors.length > 0) {
1650
+ status = exports.ValidationStatus.Error;
1651
+ }
1652
+ return {
1653
+ status: status,
1654
+ warnings: warnings,
1655
+ errors: errors,
1656
+ };
1385
1657
  }
1386
1658
  catch (err) {
1387
1659
  throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
@@ -1405,45 +1677,40 @@ class SpecParser {
1405
1677
  try {
1406
1678
  yield this.loadSpec();
1407
1679
  const spec = this.spec;
1408
- const apiMap = this.getAllSupportedAPIs(spec);
1680
+ const apiMap = this.getAPIs(spec);
1409
1681
  const result = {
1410
- validAPIs: [],
1682
+ APIs: [],
1411
1683
  allAPICount: 0,
1412
1684
  validAPICount: 0,
1413
1685
  };
1414
1686
  for (const apiKey in apiMap) {
1687
+ const { operation, isValid, reason } = apiMap[apiKey];
1688
+ const [method, path] = apiKey.split(" ");
1689
+ const operationId = (_a = operation.operationId) !== null && _a !== void 0 ? _a : `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
1415
1690
  const apiResult = {
1416
- api: "",
1691
+ api: apiKey,
1417
1692
  server: "",
1418
- operationId: "",
1693
+ operationId: operationId,
1694
+ isValid: isValid,
1695
+ reason: reason,
1419
1696
  };
1420
- const [method, path] = apiKey.split(" ");
1421
- const operation = apiMap[apiKey];
1422
- const rootServer = spec.servers && spec.servers[0];
1423
- const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
1424
- const operationServer = operation.servers && operation.servers[0];
1425
- const serverUrl = operationServer || methodServer || rootServer;
1426
- if (!serverUrl) {
1427
- throw new SpecParserError(ConstantString.NoServerInformation, exports.ErrorType.NoServerInformation);
1428
- }
1429
- apiResult.server = Utils.resolveServerUrl(serverUrl.url);
1430
- let operationId = operation.operationId;
1431
- if (!operationId) {
1432
- operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
1433
- }
1434
- apiResult.operationId = operationId;
1435
- const authArray = Utils.getAuthArray(operation.security, spec);
1436
- for (const auths of authArray) {
1437
- if (auths.length === 1) {
1438
- apiResult.auth = auths[0];
1439
- break;
1697
+ if (isValid) {
1698
+ const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
1699
+ if (serverObj) {
1700
+ apiResult.server = Utils.resolveEnv(serverObj.url);
1701
+ }
1702
+ const authArray = Utils.getAuthArray(operation.security, spec);
1703
+ for (const auths of authArray) {
1704
+ if (auths.length === 1) {
1705
+ apiResult.auth = auths[0];
1706
+ break;
1707
+ }
1440
1708
  }
1441
1709
  }
1442
- apiResult.api = apiKey;
1443
- result.validAPIs.push(apiResult);
1710
+ result.APIs.push(apiResult);
1444
1711
  }
1445
- result.allAPICount = Utils.getAllAPICount(spec);
1446
- result.validAPICount = result.validAPIs.length;
1712
+ result.allAPICount = result.APIs.length;
1713
+ result.validAPICount = result.APIs.filter((api) => api.isValid).length;
1447
1714
  return result;
1448
1715
  }
1449
1716
  catch (err) {
@@ -1541,15 +1808,18 @@ class SpecParser {
1541
1808
  const newSpecs = yield this.getFilteredSpecs(filter, signal);
1542
1809
  const newUnResolvedSpec = newSpecs[0];
1543
1810
  const newSpec = newSpecs[1];
1544
- const authSet = new Set();
1545
1811
  let hasMultipleAuth = false;
1812
+ let authInfo = undefined;
1546
1813
  for (const url in newSpec.paths) {
1547
1814
  for (const method in newSpec.paths[url]) {
1548
1815
  const operation = newSpec.paths[url][method];
1549
1816
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1550
1817
  if (authArray && authArray.length > 0) {
1551
- authSet.add(authArray[0][0]);
1552
- if (authSet.size > 1) {
1818
+ const currentAuth = authArray[0][0];
1819
+ if (!authInfo) {
1820
+ authInfo = authArray[0][0];
1821
+ }
1822
+ else if (authInfo.name !== currentAuth.name) {
1553
1823
  hasMultipleAuth = true;
1554
1824
  break;
1555
1825
  }
@@ -1596,7 +1866,6 @@ class SpecParser {
1596
1866
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1597
1867
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1598
1868
  }
1599
- const authInfo = Array.from(authSet)[0];
1600
1869
  const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1601
1870
  yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1602
1871
  result.warnings.push(...warnings);
@@ -1625,13 +1894,19 @@ class SpecParser {
1625
1894
  }
1626
1895
  });
1627
1896
  }
1628
- getAllSupportedAPIs(spec) {
1629
- if (this.apiMap !== undefined) {
1630
- return this.apiMap;
1897
+ getAPIs(spec) {
1898
+ const validator = this.getValidator(spec);
1899
+ const apiMap = validator.listAPIs();
1900
+ this.apiMap = apiMap;
1901
+ return apiMap;
1902
+ }
1903
+ getValidator(spec) {
1904
+ if (this.validator) {
1905
+ return this.validator;
1631
1906
  }
1632
- const result = Utils.listSupportedAPIs(spec, this.options);
1633
- this.apiMap = result;
1634
- return result;
1907
+ const validator = ValidatorFactory.create(spec, this.options);
1908
+ this.validator = validator;
1909
+ return validator;
1635
1910
  }
1636
1911
  }
1637
1912