@microsoft/m365-spec-parser 0.2.3 → 0.2.4-alpha.679dc7df6.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,25 +100,23 @@ 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";
115
118
  ConstantString.ContainerType = "Container";
116
- ConstantString.RegistrationIdPostfix = {
117
- apiKey: "REGISTRATION_ID",
118
- oauth2: "CONFIGURATION_ID",
119
- http: "REGISTRATION_ID",
120
- openIdConnect: "REGISTRATION_ID",
121
- };
119
+ ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
122
120
  ConstantString.ResponseCodeFor20X = [
123
121
  "200",
124
122
  "201",
@@ -187,16 +185,8 @@ ConstantString.PluginManifestSchema = "https://developer.microsoft.com/json-sche
187
185
 
188
186
  // Copyright (c) Microsoft Corporation.
189
187
  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;
188
+ static isObjectSchema(schema) {
189
+ return schema.type === "object" || (!schema.type && !!schema.properties);
200
190
  }
201
191
  static containMultipleMediaTypes(bodyObject) {
202
192
  return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
@@ -212,6 +202,23 @@ class Utils {
212
202
  authScheme.flows &&
213
203
  authScheme.flows.authorizationCode);
214
204
  }
205
+ static isNotSupportedAuth(authSchemeArray) {
206
+ if (authSchemeArray.length === 0) {
207
+ return false;
208
+ }
209
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
210
+ return true;
211
+ }
212
+ for (const auths of authSchemeArray) {
213
+ if (auths.length === 1) {
214
+ if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
215
+ Utils.isBearerTokenAuth(auths[0].authScheme)) {
216
+ return false;
217
+ }
218
+ }
219
+ }
220
+ return true;
221
+ }
215
222
  static getAuthArray(securities, spec) {
216
223
  var _a;
217
224
  const result = [];
@@ -236,6 +243,20 @@ class Utils {
236
243
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
237
244
  return result;
238
245
  }
246
+ static getAuthMap(spec) {
247
+ const authMap = {};
248
+ for (const url in spec.paths) {
249
+ for (const method in spec.paths[url]) {
250
+ const operation = spec.paths[url][method];
251
+ const authArray = Utils.getAuthArray(operation.security, spec);
252
+ if (authArray && authArray.length > 0) {
253
+ const currentAuth = authArray[0][0];
254
+ authMap[operation.operationId] = currentAuth;
255
+ }
256
+ }
257
+ }
258
+ return authMap;
259
+ }
239
260
  static getAuthInfo(spec) {
240
261
  let authInfo = undefined;
241
262
  for (const url in spec.paths) {
@@ -264,27 +285,33 @@ class Utils {
264
285
  let multipleMediaType = false;
265
286
  for (const code of ConstantString.ResponseCodeFor20X) {
266
287
  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
- }
288
+ if (!responseObject) {
289
+ continue;
290
+ }
291
+ multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
292
+ if (!allowMultipleMediaType && multipleMediaType) {
293
+ json = {};
294
+ continue;
295
+ }
296
+ const mediaObj = Utils.getJsonContentType(responseObject);
297
+ if (Object.keys(mediaObj).length > 0) {
298
+ json = mediaObj;
299
+ return { json, multipleMediaType };
284
300
  }
285
301
  }
286
302
  return { json, multipleMediaType };
287
303
  }
304
+ static getJsonContentType(responseObject) {
305
+ if (responseObject.content) {
306
+ for (const contentType of Object.keys(responseObject.content)) {
307
+ // json media type can also be "application/json; charset=utf-8"
308
+ if (contentType.indexOf("application/json") >= 0) {
309
+ return responseObject.content[contentType];
310
+ }
311
+ }
312
+ }
313
+ return {};
314
+ }
288
315
  static convertPathToCamelCase(path) {
289
316
  const pathSegments = path.split(/[./{]/);
290
317
  const camelCaseSegments = pathSegments.map((segment) => {
@@ -320,7 +347,7 @@ class Utils {
320
347
  }
321
348
  return newStr;
322
349
  }
323
- static checkServerUrl(servers) {
350
+ static checkServerUrl(servers, allowHttp = false) {
324
351
  const errors = [];
325
352
  let serverUrl;
326
353
  try {
@@ -343,8 +370,7 @@ class Utils {
343
370
  data: servers,
344
371
  });
345
372
  }
346
- else if (protocol !== "https:") {
347
- // Http server url is not supported
373
+ else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
348
374
  const protocolString = protocol.slice(0, -1);
349
375
  errors.push({
350
376
  type: ErrorType.UrlProtocolNotSupported,
@@ -360,10 +386,11 @@ class Utils {
360
386
  let hasTopLevelServers = false;
361
387
  let hasPathLevelServers = false;
362
388
  let hasOperationLevelServers = false;
389
+ const allowHttp = options.projectType === ProjectType.Copilot;
363
390
  if (spec.servers && spec.servers.length >= 1) {
364
391
  hasTopLevelServers = true;
365
392
  // for multiple server, we only use the first url
366
- const serverErrors = Utils.checkServerUrl(spec.servers);
393
+ const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
367
394
  errors.push(...serverErrors);
368
395
  }
369
396
  const paths = spec.paths;
@@ -371,7 +398,7 @@ class Utils {
371
398
  const methods = paths[path];
372
399
  if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
373
400
  hasPathLevelServers = true;
374
- const serverErrors = Utils.checkServerUrl(methods.servers);
401
+ const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
375
402
  errors.push(...serverErrors);
376
403
  }
377
404
  for (const method in methods) {
@@ -379,7 +406,7 @@ class Utils {
379
406
  if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
380
407
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
381
408
  hasOperationLevelServers = true;
382
- const serverErrors = Utils.checkServerUrl(operationObject.servers);
409
+ const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
383
410
  errors.push(...serverErrors);
384
411
  }
385
412
  }
@@ -426,7 +453,7 @@ class Utils {
426
453
  optionalParams.push(parameter);
427
454
  }
428
455
  }
429
- else if (schema.type === "object") {
456
+ else if (Utils.isObjectSchema(schema)) {
430
457
  const { properties } = schema;
431
458
  for (const property in properties) {
432
459
  let isRequired = false;
@@ -540,29 +567,6 @@ class Utils {
540
567
  const serverUrl = operationServer || methodServer || rootServer;
541
568
  return serverUrl;
542
569
  }
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
570
  }
567
571
 
568
572
  // Copyright (c) Microsoft Corporation.
@@ -691,22 +695,6 @@ class Validator {
691
695
  }
692
696
  return result;
693
697
  }
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
698
  validateServer(method, path) {
711
699
  const result = { isValid: true, reason: [] };
712
700
  const serverObj = Utils.getServerObject(this.spec, method, path);
@@ -715,8 +703,8 @@ class Validator {
715
703
  result.reason.push(ErrorType.NoServerInformation);
716
704
  }
717
705
  else {
718
- // server url should be absolute url with https protocol
719
- const serverValidateResult = Utils.checkServerUrl([serverObj]);
706
+ const allowHttp = this.projectType === ProjectType.Copilot;
707
+ const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
720
708
  result.reason.push(...serverValidateResult.map((item) => item.type));
721
709
  }
722
710
  return result;
@@ -739,6 +727,9 @@ class Validator {
739
727
  reason: [ErrorType.MultipleAuthNotSupported],
740
728
  };
741
729
  }
730
+ if (this.projectType === ProjectType.Copilot) {
731
+ return { isValid: true, reason: [] };
732
+ }
742
733
  for (const auths of authSchemeArray) {
743
734
  if (auths.length === 1) {
744
735
  if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
@@ -751,125 +742,6 @@ class Validator {
751
742
  }
752
743
  return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
753
744
  }
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
745
  }
874
746
 
875
747
  // Copyright (c) Microsoft Corporation.
@@ -879,7 +751,6 @@ class CopilotValidator extends Validator {
879
751
  this.projectType = ProjectType.Copilot;
880
752
  this.options = options;
881
753
  this.spec = spec;
882
- this.checkCircularReference();
883
754
  }
884
755
  validateSpec() {
885
756
  const result = { errors: [], warnings: [] };
@@ -905,10 +776,6 @@ class CopilotValidator extends Validator {
905
776
  if (!methodAndPathResult.isValid) {
906
777
  return methodAndPathResult;
907
778
  }
908
- const circularReferenceResult = this.validateCircularReference(method, path);
909
- if (!circularReferenceResult.isValid) {
910
- return circularReferenceResult;
911
- }
912
779
  const operationObject = this.spec.paths[path][method];
913
780
  // validate auth
914
781
  const authCheckResult = this.validateAuth(method, path);
@@ -920,24 +787,6 @@ class CopilotValidator extends Validator {
920
787
  // validate server
921
788
  const validateServerResult = this.validateServer(method, path);
922
789
  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
790
  if (result.reason.length > 0) {
942
791
  result.isValid = false;
943
792
  }
@@ -1029,6 +878,108 @@ class SMEValidator extends Validator {
1029
878
  }
1030
879
  return result;
1031
880
  }
881
+ validateResponse(method, path) {
882
+ const result = { isValid: true, reason: [] };
883
+ const operationObject = this.spec.paths[path][method];
884
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
885
+ // only support response body only contains “application/json” content type
886
+ if (multipleMediaType) {
887
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
888
+ }
889
+ else if (Object.keys(json).length === 0) {
890
+ // response body should not be empty
891
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
892
+ }
893
+ return result;
894
+ }
895
+ checkPostBodySchema(schema, isRequired = false) {
896
+ var _a;
897
+ const paramResult = {
898
+ requiredNum: 0,
899
+ optionalNum: 0,
900
+ isValid: true,
901
+ reason: [],
902
+ };
903
+ if (Object.keys(schema).length === 0) {
904
+ return paramResult;
905
+ }
906
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
907
+ const isCopilot = this.projectType === ProjectType.Copilot;
908
+ if (schema.type === "string" ||
909
+ schema.type === "integer" ||
910
+ schema.type === "boolean" ||
911
+ schema.type === "number") {
912
+ if (isRequiredWithoutDefault) {
913
+ paramResult.requiredNum = paramResult.requiredNum + 1;
914
+ }
915
+ else {
916
+ paramResult.optionalNum = paramResult.optionalNum + 1;
917
+ }
918
+ }
919
+ else if (Utils.isObjectSchema(schema)) {
920
+ const { properties } = schema;
921
+ for (const property in properties) {
922
+ let isRequired = false;
923
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
924
+ isRequired = true;
925
+ }
926
+ const result = this.checkPostBodySchema(properties[property], isRequired);
927
+ paramResult.requiredNum += result.requiredNum;
928
+ paramResult.optionalNum += result.optionalNum;
929
+ paramResult.isValid = paramResult.isValid && result.isValid;
930
+ paramResult.reason.push(...result.reason);
931
+ }
932
+ }
933
+ else {
934
+ if (isRequiredWithoutDefault && !isCopilot) {
935
+ paramResult.isValid = false;
936
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
937
+ }
938
+ }
939
+ return paramResult;
940
+ }
941
+ checkParamSchema(paramObject) {
942
+ const paramResult = {
943
+ requiredNum: 0,
944
+ optionalNum: 0,
945
+ isValid: true,
946
+ reason: [],
947
+ };
948
+ if (!paramObject) {
949
+ return paramResult;
950
+ }
951
+ for (let i = 0; i < paramObject.length; i++) {
952
+ const param = paramObject[i];
953
+ const schema = param.schema;
954
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
955
+ if (param.in === "header" || param.in === "cookie") {
956
+ if (isRequiredWithoutDefault) {
957
+ paramResult.isValid = false;
958
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
959
+ }
960
+ continue;
961
+ }
962
+ if (schema.type !== "boolean" &&
963
+ schema.type !== "string" &&
964
+ schema.type !== "number" &&
965
+ schema.type !== "integer") {
966
+ if (isRequiredWithoutDefault) {
967
+ paramResult.isValid = false;
968
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
969
+ }
970
+ continue;
971
+ }
972
+ if (param.in === "query" || param.in === "path") {
973
+ if (isRequiredWithoutDefault) {
974
+ paramResult.requiredNum = paramResult.requiredNum + 1;
975
+ }
976
+ else {
977
+ paramResult.optionalNum = paramResult.optionalNum + 1;
978
+ }
979
+ }
980
+ }
981
+ return paramResult;
982
+ }
1032
983
  validateParamCount(postBodyResult, paramResult) {
1033
984
  const result = { isValid: true, reason: [] };
1034
985
  const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
@@ -1304,20 +1255,157 @@ class SpecParser {
1304
1255
  }
1305
1256
  }
1306
1257
 
1258
+ // Copyright (c) Microsoft Corporation.
1259
+ class JsonDataGenerator {
1260
+ static generate(schema) {
1261
+ return this.generateMockData(schema);
1262
+ }
1263
+ static generateMockData(schema) {
1264
+ if (this.visitedSchemas.has(schema)) {
1265
+ return null; // Prevent circular reference
1266
+ }
1267
+ this.visitedSchemas.add(schema);
1268
+ let result;
1269
+ if (schema.anyOf) {
1270
+ // Select the first schema in anyOf
1271
+ const selectedSchema = schema.anyOf[0];
1272
+ result = this.generateMockData(selectedSchema);
1273
+ }
1274
+ else if (schema.oneOf) {
1275
+ // Select the first schema in oneOf
1276
+ const selectedSchema = schema.oneOf[0];
1277
+ result = this.generateMockData(selectedSchema);
1278
+ }
1279
+ else if (schema.allOf) {
1280
+ // merge all schemas in allOf
1281
+ result = {};
1282
+ for (const subschema of schema.allOf) {
1283
+ const data = this.generateMockData(subschema);
1284
+ result = Object.assign(Object.assign({}, result), data);
1285
+ }
1286
+ }
1287
+ else {
1288
+ switch (schema.type) {
1289
+ case "string":
1290
+ if (schema.example !== undefined) {
1291
+ result = schema.example;
1292
+ }
1293
+ else if (schema.format) {
1294
+ switch (schema.format) {
1295
+ case "date-time":
1296
+ result = "2024-11-01T05:25:43.593Z";
1297
+ break;
1298
+ case "email":
1299
+ result = "example@example.com";
1300
+ break;
1301
+ case "uuid":
1302
+ result = "123e4567-e89b-12d3-a456-426614174000";
1303
+ break;
1304
+ case "ipv4":
1305
+ result = "192.168.0.1";
1306
+ break;
1307
+ case "ipv6":
1308
+ result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
1309
+ break;
1310
+ default:
1311
+ result = "example string";
1312
+ }
1313
+ }
1314
+ else {
1315
+ result = "example string";
1316
+ }
1317
+ break;
1318
+ case "number":
1319
+ if (schema.example !== undefined) {
1320
+ result = schema.example;
1321
+ }
1322
+ else if (schema.format) {
1323
+ switch (schema.format) {
1324
+ case "float":
1325
+ result = 3.14;
1326
+ break;
1327
+ case "double":
1328
+ result = 3.14159;
1329
+ break;
1330
+ default:
1331
+ result = 123;
1332
+ }
1333
+ }
1334
+ else {
1335
+ result = 123;
1336
+ }
1337
+ break;
1338
+ case "integer":
1339
+ if (schema.example !== undefined) {
1340
+ result = schema.example;
1341
+ }
1342
+ else if (schema.format) {
1343
+ switch (schema.format) {
1344
+ case "int32":
1345
+ result = 123456;
1346
+ break;
1347
+ case "int64":
1348
+ result = 123456789;
1349
+ break;
1350
+ default:
1351
+ result = 123;
1352
+ }
1353
+ }
1354
+ else {
1355
+ result = 123;
1356
+ }
1357
+ break;
1358
+ case "boolean":
1359
+ result = schema.example !== undefined ? schema.example : true;
1360
+ break;
1361
+ case "array":
1362
+ result = [this.generateMockData(schema.items)];
1363
+ break;
1364
+ case "object":
1365
+ result = {};
1366
+ if (schema.properties) {
1367
+ for (const key in schema.properties) {
1368
+ result[key] = this.generateMockData(schema.properties[key]);
1369
+ }
1370
+ }
1371
+ break;
1372
+ default:
1373
+ result = schema.example || null;
1374
+ }
1375
+ }
1376
+ this.visitedSchemas.delete(schema);
1377
+ return result;
1378
+ }
1379
+ }
1380
+ JsonDataGenerator.visitedSchemas = new Set();
1381
+
1307
1382
  // Copyright (c) Microsoft Corporation.
1308
1383
  class AdaptiveCardGenerator {
1309
- static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
1384
+ static generateAdaptiveCard(operationItem, allowMultipleMediaType = false, maxElementCount = Number.MAX_SAFE_INTEGER) {
1310
1385
  try {
1311
1386
  const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
1312
1387
  let cardBody = [];
1388
+ let jsonData = {};
1389
+ const warnings = [];
1390
+ const operationId = operationItem.operationId;
1313
1391
  let schema = json.schema;
1314
1392
  let jsonPath = "$";
1315
1393
  if (schema && Object.keys(schema).length > 0) {
1394
+ try {
1395
+ jsonData = JsonDataGenerator.generate(schema);
1396
+ }
1397
+ catch (err) {
1398
+ warnings.push({
1399
+ type: WarningType.GenerateJsonDataFailed,
1400
+ content: Utils.format(ConstantString.GenerateJsonDataFailed, operationId, err.toString()),
1401
+ data: operationId,
1402
+ });
1403
+ }
1316
1404
  jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
1317
1405
  if (jsonPath !== "$") {
1318
1406
  schema = schema.properties[jsonPath];
1319
1407
  }
1320
- cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
1408
+ cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "", "", maxElementCount);
1321
1409
  }
1322
1410
  // if no schema, try to use example value
1323
1411
  if (cardBody.length === 0 && (json.examples || json.example)) {
@@ -1345,16 +1433,20 @@ class AdaptiveCardGenerator {
1345
1433
  version: ConstantString.AdaptiveCardVersion,
1346
1434
  body: cardBody,
1347
1435
  };
1348
- return [fullCard, jsonPath];
1436
+ return [fullCard, jsonPath, jsonData, warnings];
1349
1437
  }
1350
1438
  catch (err) {
1351
1439
  throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
1352
1440
  }
1353
1441
  }
1354
- static generateCardFromResponse(schema, name, parentArrayName = "") {
1442
+ static generateCardFromResponse(schema, name, parentArrayName = "", maxElementCount = Number.MAX_SAFE_INTEGER, counter = { count: 0 }) {
1443
+ if (counter.count >= maxElementCount) {
1444
+ return [];
1445
+ }
1355
1446
  if (schema.type === "array") {
1356
1447
  // schema.items can be arbitrary object: schema { type: array, items: {} }
1357
1448
  if (Object.keys(schema.items).length === 0) {
1449
+ counter.count++;
1358
1450
  return [
1359
1451
  {
1360
1452
  type: ConstantString.TextBlockType,
@@ -1363,7 +1455,7 @@ class AdaptiveCardGenerator {
1363
1455
  },
1364
1456
  ];
1365
1457
  }
1366
- const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
1458
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name, maxElementCount, counter);
1367
1459
  const template = {
1368
1460
  type: ConstantString.ContainerType,
1369
1461
  $data: name ? `\${${name}}` : "${$root}",
@@ -1373,11 +1465,11 @@ class AdaptiveCardGenerator {
1373
1465
  return [template];
1374
1466
  }
1375
1467
  // some schema may not contain type but contain properties
1376
- if (schema.type === "object" || (!schema.type && schema.properties)) {
1468
+ if (Utils.isObjectSchema(schema)) {
1377
1469
  const { properties } = schema;
1378
1470
  const result = [];
1379
1471
  for (const property in properties) {
1380
- const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
1472
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName, maxElementCount, counter);
1381
1473
  result.push(...obj);
1382
1474
  }
1383
1475
  if (schema.additionalProperties) {
@@ -1390,6 +1482,7 @@ class AdaptiveCardGenerator {
1390
1482
  schema.type === "integer" ||
1391
1483
  schema.type === "boolean" ||
1392
1484
  schema.type === "number") {
1485
+ counter.count++;
1393
1486
  if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
1394
1487
  // string in root: "ddd"
1395
1488
  let text = "result: ${$root}";
@@ -1414,24 +1507,17 @@ class AdaptiveCardGenerator {
1414
1507
  ];
1415
1508
  }
1416
1509
  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
- }
1510
+ const url = name ? `\${${name}}` : "${$data}";
1511
+ const condition = name
1512
+ ? `\${${name} != null && ${name} != ''}`
1513
+ : "${$data != null && $data != ''}";
1514
+ return [
1515
+ {
1516
+ type: "Image",
1517
+ url,
1518
+ $when: condition,
1519
+ },
1520
+ ];
1435
1521
  }
1436
1522
  }
1437
1523
  if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
@@ -1441,7 +1527,7 @@ class AdaptiveCardGenerator {
1441
1527
  }
1442
1528
  // Find the first array property in the response schema object with the well-known name
1443
1529
  static getResponseJsonPathFromSchema(schema) {
1444
- if (schema.type === "object" || (!schema.type && schema.properties)) {
1530
+ if (Utils.isObjectSchema(schema)) {
1445
1531
  const { properties } = schema;
1446
1532
  for (const property in properties) {
1447
1533
  const schema = properties[property];