@microsoft/m365-spec-parser 0.2.3 → 0.2.4-alpha.ad0d7aa1a.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.
@@ -32,11 +32,8 @@ var ErrorType;
32
32
  ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
33
33
  ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
34
34
  ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
35
- ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
36
35
  ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
37
36
  ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
38
- ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
39
- ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
40
37
  ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
41
38
  ErrorType["NoParameter"] = "no-parameter";
42
39
  ErrorType["NoAPIInfo"] = "no-api-info";
@@ -55,6 +52,9 @@ var WarningType;
55
52
  WarningType["OperationOnlyContainsOptionalParam"] = "operation-only-contains-optional-param";
56
53
  WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
57
54
  WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
55
+ WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
56
+ WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
57
+ WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
58
58
  WarningType["Unknown"] = "unknown";
59
59
  })(WarningType || (WarningType = {}));
60
60
  /**
@@ -100,15 +100,18 @@ ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converte
100
100
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
101
101
  ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
102
102
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
103
+ ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
104
+ ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
103
105
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
104
106
  ConstantString.FuncDescriptionTooLong = "The description of the function '%s' is too long. The current length is %s characters, while the maximum allowed length is %s characters.";
107
+ ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
105
108
  ConstantString.WrappedCardVersion = "devPreview";
106
109
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
107
110
  ConstantString.WrappedCardResponseLayout = "list";
108
111
  ConstantString.GetMethod = "get";
109
112
  ConstantString.PostMethod = "post";
110
113
  ConstantString.AdaptiveCardVersion = "1.5";
111
- ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
114
+ ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
112
115
  ConstantString.AdaptiveCardType = "AdaptiveCard";
113
116
  ConstantString.TextBlockType = "TextBlock";
114
117
  ConstantString.ImageType = "Image";
@@ -187,16 +190,8 @@ ConstantString.PluginManifestSchema = "https://developer.microsoft.com/json-sche
187
190
 
188
191
  // Copyright (c) Microsoft Corporation.
189
192
  class Utils {
190
- static hasNestedObjectInSchema(schema) {
191
- if (schema.type === "object") {
192
- for (const property in schema.properties) {
193
- const nestedSchema = schema.properties[property];
194
- if (nestedSchema.type === "object") {
195
- return true;
196
- }
197
- }
198
- }
199
- return false;
193
+ static isObjectSchema(schema) {
194
+ return schema.type === "object" || (!schema.type && !!schema.properties);
200
195
  }
201
196
  static containMultipleMediaTypes(bodyObject) {
202
197
  return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
@@ -212,6 +207,23 @@ class Utils {
212
207
  authScheme.flows &&
213
208
  authScheme.flows.authorizationCode);
214
209
  }
210
+ static isNotSupportedAuth(authSchemeArray) {
211
+ if (authSchemeArray.length === 0) {
212
+ return false;
213
+ }
214
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
215
+ return true;
216
+ }
217
+ for (const auths of authSchemeArray) {
218
+ if (auths.length === 1) {
219
+ if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
220
+ Utils.isBearerTokenAuth(auths[0].authScheme)) {
221
+ return false;
222
+ }
223
+ }
224
+ }
225
+ return true;
226
+ }
215
227
  static getAuthArray(securities, spec) {
216
228
  var _a;
217
229
  const result = [];
@@ -264,27 +276,33 @@ class Utils {
264
276
  let multipleMediaType = false;
265
277
  for (const code of ConstantString.ResponseCodeFor20X) {
266
278
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
267
- if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
268
- for (const contentType of Object.keys(responseObject.content)) {
269
- // json media type can also be "application/json; charset=utf-8"
270
- if (contentType.indexOf("application/json") >= 0) {
271
- multipleMediaType = false;
272
- json = responseObject.content[contentType];
273
- if (Utils.containMultipleMediaTypes(responseObject)) {
274
- multipleMediaType = true;
275
- if (!allowMultipleMediaType) {
276
- json = {};
277
- }
278
- }
279
- else {
280
- return { json, multipleMediaType };
281
- }
282
- }
283
- }
279
+ if (!responseObject) {
280
+ continue;
281
+ }
282
+ multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
283
+ if (!allowMultipleMediaType && multipleMediaType) {
284
+ json = {};
285
+ continue;
286
+ }
287
+ const mediaObj = Utils.getJsonContentType(responseObject);
288
+ if (Object.keys(mediaObj).length > 0) {
289
+ json = mediaObj;
290
+ return { json, multipleMediaType };
284
291
  }
285
292
  }
286
293
  return { json, multipleMediaType };
287
294
  }
295
+ static getJsonContentType(responseObject) {
296
+ if (responseObject.content) {
297
+ for (const contentType of Object.keys(responseObject.content)) {
298
+ // json media type can also be "application/json; charset=utf-8"
299
+ if (contentType.indexOf("application/json") >= 0) {
300
+ return responseObject.content[contentType];
301
+ }
302
+ }
303
+ }
304
+ return {};
305
+ }
288
306
  static convertPathToCamelCase(path) {
289
307
  const pathSegments = path.split(/[./{]/);
290
308
  const camelCaseSegments = pathSegments.map((segment) => {
@@ -320,7 +338,7 @@ class Utils {
320
338
  }
321
339
  return newStr;
322
340
  }
323
- static checkServerUrl(servers) {
341
+ static checkServerUrl(servers, allowHttp = false) {
324
342
  const errors = [];
325
343
  let serverUrl;
326
344
  try {
@@ -343,8 +361,7 @@ class Utils {
343
361
  data: servers,
344
362
  });
345
363
  }
346
- else if (protocol !== "https:") {
347
- // Http server url is not supported
364
+ else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
348
365
  const protocolString = protocol.slice(0, -1);
349
366
  errors.push({
350
367
  type: ErrorType.UrlProtocolNotSupported,
@@ -360,10 +377,11 @@ class Utils {
360
377
  let hasTopLevelServers = false;
361
378
  let hasPathLevelServers = false;
362
379
  let hasOperationLevelServers = false;
380
+ const allowHttp = options.projectType === ProjectType.Copilot;
363
381
  if (spec.servers && spec.servers.length >= 1) {
364
382
  hasTopLevelServers = true;
365
383
  // for multiple server, we only use the first url
366
- const serverErrors = Utils.checkServerUrl(spec.servers);
384
+ const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
367
385
  errors.push(...serverErrors);
368
386
  }
369
387
  const paths = spec.paths;
@@ -371,7 +389,7 @@ class Utils {
371
389
  const methods = paths[path];
372
390
  if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
373
391
  hasPathLevelServers = true;
374
- const serverErrors = Utils.checkServerUrl(methods.servers);
392
+ const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
375
393
  errors.push(...serverErrors);
376
394
  }
377
395
  for (const method in methods) {
@@ -379,7 +397,7 @@ class Utils {
379
397
  if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
380
398
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
381
399
  hasOperationLevelServers = true;
382
- const serverErrors = Utils.checkServerUrl(operationObject.servers);
400
+ const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
383
401
  errors.push(...serverErrors);
384
402
  }
385
403
  }
@@ -426,7 +444,7 @@ class Utils {
426
444
  optionalParams.push(parameter);
427
445
  }
428
446
  }
429
- else if (schema.type === "object") {
447
+ else if (Utils.isObjectSchema(schema)) {
430
448
  const { properties } = schema;
431
449
  for (const property in properties) {
432
450
  let isRequired = false;
@@ -540,29 +558,6 @@ class Utils {
540
558
  const serverUrl = operationServer || methodServer || rootServer;
541
559
  return serverUrl;
542
560
  }
543
- static limitACBodyProperties(body, maxCount) {
544
- const result = [];
545
- let currentCount = 0;
546
- for (const element of body) {
547
- if (element.type === ConstantString.ContainerType) {
548
- const items = this.limitACBodyProperties(element.items, maxCount - currentCount);
549
- result.push({
550
- type: ConstantString.ContainerType,
551
- $data: element.$data,
552
- items: items,
553
- });
554
- currentCount += items.length;
555
- }
556
- else {
557
- result.push(element);
558
- currentCount++;
559
- }
560
- if (currentCount >= maxCount) {
561
- break;
562
- }
563
- }
564
- return result;
565
- }
566
561
  }
567
562
 
568
563
  // Copyright (c) Microsoft Corporation.
@@ -691,22 +686,6 @@ class Validator {
691
686
  }
692
687
  return result;
693
688
  }
694
- validateResponse(method, path) {
695
- const result = { isValid: true, reason: [] };
696
- const operationObject = this.spec.paths[path][method];
697
- const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
698
- if (this.options.projectType === ProjectType.SME) {
699
- // only support response body only contains “application/json” content type
700
- if (multipleMediaType) {
701
- result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
702
- }
703
- else if (Object.keys(json).length === 0) {
704
- // response body should not be empty
705
- result.reason.push(ErrorType.ResponseJsonIsEmpty);
706
- }
707
- }
708
- return result;
709
- }
710
689
  validateServer(method, path) {
711
690
  const result = { isValid: true, reason: [] };
712
691
  const serverObj = Utils.getServerObject(this.spec, method, path);
@@ -715,8 +694,8 @@ class Validator {
715
694
  result.reason.push(ErrorType.NoServerInformation);
716
695
  }
717
696
  else {
718
- // server url should be absolute url with https protocol
719
- const serverValidateResult = Utils.checkServerUrl([serverObj]);
697
+ const allowHttp = this.projectType === ProjectType.Copilot;
698
+ const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
720
699
  result.reason.push(...serverValidateResult.map((item) => item.type));
721
700
  }
722
701
  return result;
@@ -739,6 +718,9 @@ class Validator {
739
718
  reason: [ErrorType.MultipleAuthNotSupported],
740
719
  };
741
720
  }
721
+ if (this.projectType === ProjectType.Copilot) {
722
+ return { isValid: true, reason: [] };
723
+ }
742
724
  for (const auths of authSchemeArray) {
743
725
  if (auths.length === 1) {
744
726
  if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
@@ -751,125 +733,6 @@ class Validator {
751
733
  }
752
734
  return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
753
735
  }
754
- checkPostBodySchema(schema, isRequired = false) {
755
- var _a;
756
- const paramResult = {
757
- requiredNum: 0,
758
- optionalNum: 0,
759
- isValid: true,
760
- reason: [],
761
- };
762
- if (Object.keys(schema).length === 0) {
763
- return paramResult;
764
- }
765
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
766
- const isCopilot = this.projectType === ProjectType.Copilot;
767
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
768
- paramResult.isValid = false;
769
- paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
770
- return paramResult;
771
- }
772
- if (schema.type === "string" ||
773
- schema.type === "integer" ||
774
- schema.type === "boolean" ||
775
- schema.type === "number") {
776
- if (isRequiredWithoutDefault) {
777
- paramResult.requiredNum = paramResult.requiredNum + 1;
778
- }
779
- else {
780
- paramResult.optionalNum = paramResult.optionalNum + 1;
781
- }
782
- }
783
- else if (schema.type === "object") {
784
- const { properties } = schema;
785
- for (const property in properties) {
786
- let isRequired = false;
787
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
788
- isRequired = true;
789
- }
790
- const result = this.checkPostBodySchema(properties[property], isRequired);
791
- paramResult.requiredNum += result.requiredNum;
792
- paramResult.optionalNum += result.optionalNum;
793
- paramResult.isValid = paramResult.isValid && result.isValid;
794
- paramResult.reason.push(...result.reason);
795
- }
796
- }
797
- else {
798
- if (isRequiredWithoutDefault && !isCopilot) {
799
- paramResult.isValid = false;
800
- paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
801
- }
802
- }
803
- return paramResult;
804
- }
805
- checkParamSchema(paramObject) {
806
- const paramResult = {
807
- requiredNum: 0,
808
- optionalNum: 0,
809
- isValid: true,
810
- reason: [],
811
- };
812
- if (!paramObject) {
813
- return paramResult;
814
- }
815
- const isCopilot = this.projectType === ProjectType.Copilot;
816
- for (let i = 0; i < paramObject.length; i++) {
817
- const param = paramObject[i];
818
- const schema = param.schema;
819
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
820
- paramResult.isValid = false;
821
- paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
822
- continue;
823
- }
824
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
825
- if (isCopilot) {
826
- if (isRequiredWithoutDefault) {
827
- paramResult.requiredNum = paramResult.requiredNum + 1;
828
- }
829
- else {
830
- paramResult.optionalNum = paramResult.optionalNum + 1;
831
- }
832
- continue;
833
- }
834
- if (param.in === "header" || param.in === "cookie") {
835
- if (isRequiredWithoutDefault) {
836
- paramResult.isValid = false;
837
- paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
838
- }
839
- continue;
840
- }
841
- if (schema.type !== "boolean" &&
842
- schema.type !== "string" &&
843
- schema.type !== "number" &&
844
- schema.type !== "integer") {
845
- if (isRequiredWithoutDefault) {
846
- paramResult.isValid = false;
847
- paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
848
- }
849
- continue;
850
- }
851
- if (param.in === "query" || param.in === "path") {
852
- if (isRequiredWithoutDefault) {
853
- paramResult.requiredNum = paramResult.requiredNum + 1;
854
- }
855
- else {
856
- paramResult.optionalNum = paramResult.optionalNum + 1;
857
- }
858
- }
859
- }
860
- return paramResult;
861
- }
862
- hasNestedObjectInSchema(schema) {
863
- if (schema.type === "object") {
864
- for (const property in schema.properties) {
865
- const nestedSchema = schema.properties[property];
866
- if (nestedSchema.type === "object") {
867
- return true;
868
- }
869
- }
870
- }
871
- return false;
872
- }
873
736
  }
874
737
 
875
738
  // Copyright (c) Microsoft Corporation.
@@ -879,7 +742,6 @@ class CopilotValidator extends Validator {
879
742
  this.projectType = ProjectType.Copilot;
880
743
  this.options = options;
881
744
  this.spec = spec;
882
- this.checkCircularReference();
883
745
  }
884
746
  validateSpec() {
885
747
  const result = { errors: [], warnings: [] };
@@ -905,10 +767,6 @@ class CopilotValidator extends Validator {
905
767
  if (!methodAndPathResult.isValid) {
906
768
  return methodAndPathResult;
907
769
  }
908
- const circularReferenceResult = this.validateCircularReference(method, path);
909
- if (!circularReferenceResult.isValid) {
910
- return circularReferenceResult;
911
- }
912
770
  const operationObject = this.spec.paths[path][method];
913
771
  // validate auth
914
772
  const authCheckResult = this.validateAuth(method, path);
@@ -920,24 +778,6 @@ class CopilotValidator extends Validator {
920
778
  // validate server
921
779
  const validateServerResult = this.validateServer(method, path);
922
780
  result.reason.push(...validateServerResult.reason);
923
- // validate response
924
- const validateResponseResult = this.validateResponse(method, path);
925
- result.reason.push(...validateResponseResult.reason);
926
- // validate requestBody
927
- const requestBody = operationObject.requestBody;
928
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
929
- if (requestJsonBody) {
930
- const requestBodySchema = requestJsonBody.schema;
931
- if (requestBodySchema.type !== "object") {
932
- result.reason.push(ErrorType.PostBodySchemaIsNotJson);
933
- }
934
- const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
935
- result.reason.push(...requestBodyParamResult.reason);
936
- }
937
- // validate parameters
938
- const paramObject = operationObject.parameters;
939
- const paramResult = this.checkParamSchema(paramObject);
940
- result.reason.push(...paramResult.reason);
941
781
  if (result.reason.length > 0) {
942
782
  result.isValid = false;
943
783
  }
@@ -1029,6 +869,108 @@ class SMEValidator extends Validator {
1029
869
  }
1030
870
  return result;
1031
871
  }
872
+ validateResponse(method, path) {
873
+ const result = { isValid: true, reason: [] };
874
+ const operationObject = this.spec.paths[path][method];
875
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
876
+ // only support response body only contains “application/json” content type
877
+ if (multipleMediaType) {
878
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
879
+ }
880
+ else if (Object.keys(json).length === 0) {
881
+ // response body should not be empty
882
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
883
+ }
884
+ return result;
885
+ }
886
+ checkPostBodySchema(schema, isRequired = false) {
887
+ var _a;
888
+ const paramResult = {
889
+ requiredNum: 0,
890
+ optionalNum: 0,
891
+ isValid: true,
892
+ reason: [],
893
+ };
894
+ if (Object.keys(schema).length === 0) {
895
+ return paramResult;
896
+ }
897
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
898
+ const isCopilot = this.projectType === ProjectType.Copilot;
899
+ if (schema.type === "string" ||
900
+ schema.type === "integer" ||
901
+ schema.type === "boolean" ||
902
+ schema.type === "number") {
903
+ if (isRequiredWithoutDefault) {
904
+ paramResult.requiredNum = paramResult.requiredNum + 1;
905
+ }
906
+ else {
907
+ paramResult.optionalNum = paramResult.optionalNum + 1;
908
+ }
909
+ }
910
+ else if (Utils.isObjectSchema(schema)) {
911
+ const { properties } = schema;
912
+ for (const property in properties) {
913
+ let isRequired = false;
914
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
915
+ isRequired = true;
916
+ }
917
+ const result = this.checkPostBodySchema(properties[property], isRequired);
918
+ paramResult.requiredNum += result.requiredNum;
919
+ paramResult.optionalNum += result.optionalNum;
920
+ paramResult.isValid = paramResult.isValid && result.isValid;
921
+ paramResult.reason.push(...result.reason);
922
+ }
923
+ }
924
+ else {
925
+ if (isRequiredWithoutDefault && !isCopilot) {
926
+ paramResult.isValid = false;
927
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
928
+ }
929
+ }
930
+ return paramResult;
931
+ }
932
+ checkParamSchema(paramObject) {
933
+ const paramResult = {
934
+ requiredNum: 0,
935
+ optionalNum: 0,
936
+ isValid: true,
937
+ reason: [],
938
+ };
939
+ if (!paramObject) {
940
+ return paramResult;
941
+ }
942
+ for (let i = 0; i < paramObject.length; i++) {
943
+ const param = paramObject[i];
944
+ const schema = param.schema;
945
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
946
+ if (param.in === "header" || param.in === "cookie") {
947
+ if (isRequiredWithoutDefault) {
948
+ paramResult.isValid = false;
949
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
950
+ }
951
+ continue;
952
+ }
953
+ if (schema.type !== "boolean" &&
954
+ schema.type !== "string" &&
955
+ schema.type !== "number" &&
956
+ schema.type !== "integer") {
957
+ if (isRequiredWithoutDefault) {
958
+ paramResult.isValid = false;
959
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
960
+ }
961
+ continue;
962
+ }
963
+ if (param.in === "query" || param.in === "path") {
964
+ if (isRequiredWithoutDefault) {
965
+ paramResult.requiredNum = paramResult.requiredNum + 1;
966
+ }
967
+ else {
968
+ paramResult.optionalNum = paramResult.optionalNum + 1;
969
+ }
970
+ }
971
+ }
972
+ return paramResult;
973
+ }
1032
974
  validateParamCount(postBodyResult, paramResult) {
1033
975
  const result = { isValid: true, reason: [] };
1034
976
  const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
@@ -1304,20 +1246,157 @@ class SpecParser {
1304
1246
  }
1305
1247
  }
1306
1248
 
1249
+ // Copyright (c) Microsoft Corporation.
1250
+ class JsonDataGenerator {
1251
+ static generate(schema) {
1252
+ return this.generateMockData(schema);
1253
+ }
1254
+ static generateMockData(schema) {
1255
+ if (this.visitedSchemas.has(schema)) {
1256
+ return null; // Prevent circular reference
1257
+ }
1258
+ this.visitedSchemas.add(schema);
1259
+ let result;
1260
+ if (schema.anyOf) {
1261
+ // Select the first schema in anyOf
1262
+ const selectedSchema = schema.anyOf[0];
1263
+ result = this.generateMockData(selectedSchema);
1264
+ }
1265
+ else if (schema.oneOf) {
1266
+ // Select the first schema in oneOf
1267
+ const selectedSchema = schema.oneOf[0];
1268
+ result = this.generateMockData(selectedSchema);
1269
+ }
1270
+ else if (schema.allOf) {
1271
+ // merge all schemas in allOf
1272
+ result = {};
1273
+ for (const subschema of schema.allOf) {
1274
+ const data = this.generateMockData(subschema);
1275
+ result = Object.assign(Object.assign({}, result), data);
1276
+ }
1277
+ }
1278
+ else {
1279
+ switch (schema.type) {
1280
+ case "string":
1281
+ if (schema.example !== undefined) {
1282
+ result = schema.example;
1283
+ }
1284
+ else if (schema.format) {
1285
+ switch (schema.format) {
1286
+ case "date-time":
1287
+ result = "2024-11-01T05:25:43.593Z";
1288
+ break;
1289
+ case "email":
1290
+ result = "example@example.com";
1291
+ break;
1292
+ case "uuid":
1293
+ result = "123e4567-e89b-12d3-a456-426614174000";
1294
+ break;
1295
+ case "ipv4":
1296
+ result = "192.168.0.1";
1297
+ break;
1298
+ case "ipv6":
1299
+ result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
1300
+ break;
1301
+ default:
1302
+ result = "example string";
1303
+ }
1304
+ }
1305
+ else {
1306
+ result = "example string";
1307
+ }
1308
+ break;
1309
+ case "number":
1310
+ if (schema.example !== undefined) {
1311
+ result = schema.example;
1312
+ }
1313
+ else if (schema.format) {
1314
+ switch (schema.format) {
1315
+ case "float":
1316
+ result = 3.14;
1317
+ break;
1318
+ case "double":
1319
+ result = 3.14159;
1320
+ break;
1321
+ default:
1322
+ result = 123;
1323
+ }
1324
+ }
1325
+ else {
1326
+ result = 123;
1327
+ }
1328
+ break;
1329
+ case "integer":
1330
+ if (schema.example !== undefined) {
1331
+ result = schema.example;
1332
+ }
1333
+ else if (schema.format) {
1334
+ switch (schema.format) {
1335
+ case "int32":
1336
+ result = 123456;
1337
+ break;
1338
+ case "int64":
1339
+ result = 123456789;
1340
+ break;
1341
+ default:
1342
+ result = 123;
1343
+ }
1344
+ }
1345
+ else {
1346
+ result = 123;
1347
+ }
1348
+ break;
1349
+ case "boolean":
1350
+ result = schema.example !== undefined ? schema.example : true;
1351
+ break;
1352
+ case "array":
1353
+ result = [this.generateMockData(schema.items)];
1354
+ break;
1355
+ case "object":
1356
+ result = {};
1357
+ if (schema.properties) {
1358
+ for (const key in schema.properties) {
1359
+ result[key] = this.generateMockData(schema.properties[key]);
1360
+ }
1361
+ }
1362
+ break;
1363
+ default:
1364
+ result = schema.example || null;
1365
+ }
1366
+ }
1367
+ this.visitedSchemas.delete(schema);
1368
+ return result;
1369
+ }
1370
+ }
1371
+ JsonDataGenerator.visitedSchemas = new Set();
1372
+
1307
1373
  // Copyright (c) Microsoft Corporation.
1308
1374
  class AdaptiveCardGenerator {
1309
- static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
1375
+ static generateAdaptiveCard(operationItem, allowMultipleMediaType = false, maxElementCount = Number.MAX_SAFE_INTEGER) {
1310
1376
  try {
1311
1377
  const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
1312
1378
  let cardBody = [];
1379
+ let jsonData = {};
1380
+ const warnings = [];
1381
+ const operationId = operationItem.operationId;
1313
1382
  let schema = json.schema;
1314
1383
  let jsonPath = "$";
1315
1384
  if (schema && Object.keys(schema).length > 0) {
1385
+ try {
1386
+ jsonData = JsonDataGenerator.generate(schema);
1387
+ }
1388
+ catch (err) {
1389
+ warnings.push({
1390
+ type: WarningType.GenerateJsonDataFailed,
1391
+ content: Utils.format(ConstantString.GenerateJsonDataFailed, operationId, err.toString()),
1392
+ data: operationId,
1393
+ });
1394
+ }
1316
1395
  jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
1317
1396
  if (jsonPath !== "$") {
1318
1397
  schema = schema.properties[jsonPath];
1319
1398
  }
1320
- cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
1399
+ cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "", "", maxElementCount);
1321
1400
  }
1322
1401
  // if no schema, try to use example value
1323
1402
  if (cardBody.length === 0 && (json.examples || json.example)) {
@@ -1345,16 +1424,20 @@ class AdaptiveCardGenerator {
1345
1424
  version: ConstantString.AdaptiveCardVersion,
1346
1425
  body: cardBody,
1347
1426
  };
1348
- return [fullCard, jsonPath];
1427
+ return [fullCard, jsonPath, jsonData, warnings];
1349
1428
  }
1350
1429
  catch (err) {
1351
1430
  throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
1352
1431
  }
1353
1432
  }
1354
- static generateCardFromResponse(schema, name, parentArrayName = "") {
1433
+ static generateCardFromResponse(schema, name, parentArrayName = "", maxElementCount = Number.MAX_SAFE_INTEGER, counter = { count: 0 }) {
1434
+ if (counter.count >= maxElementCount) {
1435
+ return [];
1436
+ }
1355
1437
  if (schema.type === "array") {
1356
1438
  // schema.items can be arbitrary object: schema { type: array, items: {} }
1357
1439
  if (Object.keys(schema.items).length === 0) {
1440
+ counter.count++;
1358
1441
  return [
1359
1442
  {
1360
1443
  type: ConstantString.TextBlockType,
@@ -1363,7 +1446,7 @@ class AdaptiveCardGenerator {
1363
1446
  },
1364
1447
  ];
1365
1448
  }
1366
- const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
1449
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name, maxElementCount, counter);
1367
1450
  const template = {
1368
1451
  type: ConstantString.ContainerType,
1369
1452
  $data: name ? `\${${name}}` : "${$root}",
@@ -1373,11 +1456,11 @@ class AdaptiveCardGenerator {
1373
1456
  return [template];
1374
1457
  }
1375
1458
  // some schema may not contain type but contain properties
1376
- if (schema.type === "object" || (!schema.type && schema.properties)) {
1459
+ if (Utils.isObjectSchema(schema)) {
1377
1460
  const { properties } = schema;
1378
1461
  const result = [];
1379
1462
  for (const property in properties) {
1380
- const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
1463
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName, maxElementCount, counter);
1381
1464
  result.push(...obj);
1382
1465
  }
1383
1466
  if (schema.additionalProperties) {
@@ -1390,6 +1473,7 @@ class AdaptiveCardGenerator {
1390
1473
  schema.type === "integer" ||
1391
1474
  schema.type === "boolean" ||
1392
1475
  schema.type === "number") {
1476
+ counter.count++;
1393
1477
  if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
1394
1478
  // string in root: "ddd"
1395
1479
  let text = "result: ${$root}";
@@ -1414,24 +1498,17 @@ class AdaptiveCardGenerator {
1414
1498
  ];
1415
1499
  }
1416
1500
  else {
1417
- if (name) {
1418
- return [
1419
- {
1420
- type: "Image",
1421
- url: `\${${name}}`,
1422
- $when: `\${${name} != null && ${name} != ''}`,
1423
- },
1424
- ];
1425
- }
1426
- else {
1427
- return [
1428
- {
1429
- type: "Image",
1430
- url: "${$data}",
1431
- $when: "${$data != null && $data != ''}",
1432
- },
1433
- ];
1434
- }
1501
+ const url = name ? `\${${name}}` : "${$data}";
1502
+ const condition = name
1503
+ ? `\${${name} != null && ${name} != ''}`
1504
+ : "${$data != null && $data != ''}";
1505
+ return [
1506
+ {
1507
+ type: "Image",
1508
+ url,
1509
+ $when: condition,
1510
+ },
1511
+ ];
1435
1512
  }
1436
1513
  }
1437
1514
  if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
@@ -1441,7 +1518,7 @@ class AdaptiveCardGenerator {
1441
1518
  }
1442
1519
  // Find the first array property in the response schema object with the well-known name
1443
1520
  static getResponseJsonPathFromSchema(schema) {
1444
- if (schema.type === "object" || (!schema.type && schema.properties)) {
1521
+ if (Utils.isObjectSchema(schema)) {
1445
1522
  const { properties } = schema;
1446
1523
  for (const property in properties) {
1447
1524
  const schema = properties[property];