@microsoft/m365-spec-parser 0.2.3-rc-hotfix.3 → 0.2.4-alpha.396238b05.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,11 +62,8 @@ var ErrorType;
62
62
  ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
63
63
  ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
64
64
  ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
65
- ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
66
65
  ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
67
66
  ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
68
- ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
69
- ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
70
67
  ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
71
68
  ErrorType["NoParameter"] = "no-parameter";
72
69
  ErrorType["NoAPIInfo"] = "no-api-info";
@@ -85,6 +82,9 @@ var WarningType;
85
82
  WarningType["OperationOnlyContainsOptionalParam"] = "operation-only-contains-optional-param";
86
83
  WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
87
84
  WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
85
+ WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
86
+ WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
87
+ WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
88
88
  WarningType["Unknown"] = "unknown";
89
89
  })(WarningType || (WarningType = {}));
90
90
  /**
@@ -130,25 +130,23 @@ ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converte
130
130
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
131
131
  ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
132
132
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
133
+ ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
134
+ ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
133
135
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
134
136
  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.";
137
+ ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
135
138
  ConstantString.WrappedCardVersion = "devPreview";
136
139
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
137
140
  ConstantString.WrappedCardResponseLayout = "list";
138
141
  ConstantString.GetMethod = "get";
139
142
  ConstantString.PostMethod = "post";
140
143
  ConstantString.AdaptiveCardVersion = "1.5";
141
- ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
144
+ ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
142
145
  ConstantString.AdaptiveCardType = "AdaptiveCard";
143
146
  ConstantString.TextBlockType = "TextBlock";
144
147
  ConstantString.ImageType = "Image";
145
148
  ConstantString.ContainerType = "Container";
146
- ConstantString.RegistrationIdPostfix = {
147
- apiKey: "REGISTRATION_ID",
148
- oauth2: "CONFIGURATION_ID",
149
- http: "REGISTRATION_ID",
150
- openIdConnect: "REGISTRATION_ID",
151
- };
149
+ ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
152
150
  ConstantString.ResponseCodeFor20X = [
153
151
  "200",
154
152
  "201",
@@ -217,16 +215,8 @@ ConstantString.PluginManifestSchema = "https://developer.microsoft.com/json-sche
217
215
 
218
216
  // Copyright (c) Microsoft Corporation.
219
217
  class Utils {
220
- static hasNestedObjectInSchema(schema) {
221
- if (schema.type === "object") {
222
- for (const property in schema.properties) {
223
- const nestedSchema = schema.properties[property];
224
- if (nestedSchema.type === "object") {
225
- return true;
226
- }
227
- }
228
- }
229
- return false;
218
+ static isObjectSchema(schema) {
219
+ return schema.type === "object" || (!schema.type && !!schema.properties);
230
220
  }
231
221
  static containMultipleMediaTypes(bodyObject) {
232
222
  return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
@@ -237,11 +227,32 @@ class Utils {
237
227
  static isAPIKeyAuth(authScheme) {
238
228
  return authScheme.type === "apiKey";
239
229
  }
230
+ static isAPIKeyAuthButNotInCookie(authScheme) {
231
+ return authScheme.type === "apiKey" && authScheme.in !== "cookie";
232
+ }
240
233
  static isOAuthWithAuthCodeFlow(authScheme) {
241
234
  return !!(authScheme.type === "oauth2" &&
242
235
  authScheme.flows &&
243
236
  authScheme.flows.authorizationCode);
244
237
  }
238
+ static isNotSupportedAuth(authSchemeArray) {
239
+ if (authSchemeArray.length === 0) {
240
+ return false;
241
+ }
242
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
243
+ return true;
244
+ }
245
+ for (const auths of authSchemeArray) {
246
+ if (auths.length === 1) {
247
+ if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
248
+ Utils.isBearerTokenAuth(auths[0].authScheme) ||
249
+ Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
250
+ return false;
251
+ }
252
+ }
253
+ }
254
+ return true;
255
+ }
245
256
  static getAuthArray(securities, spec) {
246
257
  var _a;
247
258
  const result = [];
@@ -266,6 +277,20 @@ class Utils {
266
277
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
267
278
  return result;
268
279
  }
280
+ static getAuthMap(spec) {
281
+ const authMap = {};
282
+ for (const url in spec.paths) {
283
+ for (const method in spec.paths[url]) {
284
+ const operation = spec.paths[url][method];
285
+ const authArray = Utils.getAuthArray(operation.security, spec);
286
+ if (authArray && authArray.length > 0) {
287
+ const currentAuth = authArray[0][0];
288
+ authMap[operation.operationId] = currentAuth;
289
+ }
290
+ }
291
+ }
292
+ return authMap;
293
+ }
269
294
  static getAuthInfo(spec) {
270
295
  let authInfo = undefined;
271
296
  for (const url in spec.paths) {
@@ -294,27 +319,33 @@ class Utils {
294
319
  let multipleMediaType = false;
295
320
  for (const code of ConstantString.ResponseCodeFor20X) {
296
321
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
297
- if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
298
- for (const contentType of Object.keys(responseObject.content)) {
299
- // json media type can also be "application/json; charset=utf-8"
300
- if (contentType.indexOf("application/json") >= 0) {
301
- multipleMediaType = false;
302
- json = responseObject.content[contentType];
303
- if (Utils.containMultipleMediaTypes(responseObject)) {
304
- multipleMediaType = true;
305
- if (!allowMultipleMediaType) {
306
- json = {};
307
- }
308
- }
309
- else {
310
- return { json, multipleMediaType };
311
- }
312
- }
313
- }
322
+ if (!responseObject) {
323
+ continue;
324
+ }
325
+ multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
326
+ if (!allowMultipleMediaType && multipleMediaType) {
327
+ json = {};
328
+ continue;
329
+ }
330
+ const mediaObj = Utils.getJsonContentType(responseObject);
331
+ if (Object.keys(mediaObj).length > 0) {
332
+ json = mediaObj;
333
+ return { json, multipleMediaType };
314
334
  }
315
335
  }
316
336
  return { json, multipleMediaType };
317
337
  }
338
+ static getJsonContentType(responseObject) {
339
+ if (responseObject.content) {
340
+ for (const contentType of Object.keys(responseObject.content)) {
341
+ // json media type can also be "application/json; charset=utf-8"
342
+ if (contentType.indexOf("application/json") >= 0) {
343
+ return responseObject.content[contentType];
344
+ }
345
+ }
346
+ }
347
+ return {};
348
+ }
318
349
  static convertPathToCamelCase(path) {
319
350
  const pathSegments = path.split(/[./{]/);
320
351
  const camelCaseSegments = pathSegments.map((segment) => {
@@ -350,7 +381,7 @@ class Utils {
350
381
  }
351
382
  return newStr;
352
383
  }
353
- static checkServerUrl(servers) {
384
+ static checkServerUrl(servers, allowHttp = false) {
354
385
  const errors = [];
355
386
  let serverUrl;
356
387
  try {
@@ -373,8 +404,7 @@ class Utils {
373
404
  data: servers,
374
405
  });
375
406
  }
376
- else if (protocol !== "https:") {
377
- // Http server url is not supported
407
+ else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
378
408
  const protocolString = protocol.slice(0, -1);
379
409
  errors.push({
380
410
  type: ErrorType.UrlProtocolNotSupported,
@@ -390,10 +420,11 @@ class Utils {
390
420
  let hasTopLevelServers = false;
391
421
  let hasPathLevelServers = false;
392
422
  let hasOperationLevelServers = false;
423
+ const allowHttp = options.projectType === ProjectType.Copilot;
393
424
  if (spec.servers && spec.servers.length >= 1) {
394
425
  hasTopLevelServers = true;
395
426
  // for multiple server, we only use the first url
396
- const serverErrors = Utils.checkServerUrl(spec.servers);
427
+ const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
397
428
  errors.push(...serverErrors);
398
429
  }
399
430
  const paths = spec.paths;
@@ -401,7 +432,7 @@ class Utils {
401
432
  const methods = paths[path];
402
433
  if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
403
434
  hasPathLevelServers = true;
404
- const serverErrors = Utils.checkServerUrl(methods.servers);
435
+ const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
405
436
  errors.push(...serverErrors);
406
437
  }
407
438
  for (const method in methods) {
@@ -409,7 +440,7 @@ class Utils {
409
440
  if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
410
441
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
411
442
  hasOperationLevelServers = true;
412
- const serverErrors = Utils.checkServerUrl(operationObject.servers);
443
+ const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
413
444
  errors.push(...serverErrors);
414
445
  }
415
446
  }
@@ -456,7 +487,7 @@ class Utils {
456
487
  optionalParams.push(parameter);
457
488
  }
458
489
  }
459
- else if (schema.type === "object") {
490
+ else if (Utils.isObjectSchema(schema)) {
460
491
  const { properties } = schema;
461
492
  for (const property in properties) {
462
493
  let isRequired = false;
@@ -570,29 +601,6 @@ class Utils {
570
601
  const serverUrl = operationServer || methodServer || rootServer;
571
602
  return serverUrl;
572
603
  }
573
- static limitACBodyProperties(body, maxCount) {
574
- const result = [];
575
- let currentCount = 0;
576
- for (const element of body) {
577
- if (element.type === ConstantString.ContainerType) {
578
- const items = this.limitACBodyProperties(element.items, maxCount - currentCount);
579
- result.push({
580
- type: ConstantString.ContainerType,
581
- $data: element.$data,
582
- items: items,
583
- });
584
- currentCount += items.length;
585
- }
586
- else {
587
- result.push(element);
588
- currentCount++;
589
- }
590
- if (currentCount >= maxCount) {
591
- break;
592
- }
593
- }
594
- return result;
595
- }
596
604
  }
597
605
 
598
606
  // Copyright (c) Microsoft Corporation.
@@ -721,22 +729,6 @@ class Validator {
721
729
  }
722
730
  return result;
723
731
  }
724
- validateResponse(method, path) {
725
- const result = { isValid: true, reason: [] };
726
- const operationObject = this.spec.paths[path][method];
727
- const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
728
- if (this.options.projectType === ProjectType.SME) {
729
- // only support response body only contains “application/json” content type
730
- if (multipleMediaType) {
731
- result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
732
- }
733
- else if (Object.keys(json).length === 0) {
734
- // response body should not be empty
735
- result.reason.push(ErrorType.ResponseJsonIsEmpty);
736
- }
737
- }
738
- return result;
739
- }
740
732
  validateServer(method, path) {
741
733
  const result = { isValid: true, reason: [] };
742
734
  const serverObj = Utils.getServerObject(this.spec, method, path);
@@ -745,8 +737,8 @@ class Validator {
745
737
  result.reason.push(ErrorType.NoServerInformation);
746
738
  }
747
739
  else {
748
- // server url should be absolute url with https protocol
749
- const serverValidateResult = Utils.checkServerUrl([serverObj]);
740
+ const allowHttp = this.projectType === ProjectType.Copilot;
741
+ const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
750
742
  result.reason.push(...serverValidateResult.map((item) => item.type));
751
743
  }
752
744
  return result;
@@ -769,6 +761,9 @@ class Validator {
769
761
  reason: [ErrorType.MultipleAuthNotSupported],
770
762
  };
771
763
  }
764
+ if (this.projectType === ProjectType.Copilot) {
765
+ return { isValid: true, reason: [] };
766
+ }
772
767
  for (const auths of authSchemeArray) {
773
768
  if (auths.length === 1) {
774
769
  if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
@@ -781,125 +776,6 @@ class Validator {
781
776
  }
782
777
  return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
783
778
  }
784
- checkPostBodySchema(schema, isRequired = false) {
785
- var _a;
786
- const paramResult = {
787
- requiredNum: 0,
788
- optionalNum: 0,
789
- isValid: true,
790
- reason: [],
791
- };
792
- if (Object.keys(schema).length === 0) {
793
- return paramResult;
794
- }
795
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
796
- const isCopilot = this.projectType === ProjectType.Copilot;
797
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
798
- paramResult.isValid = false;
799
- paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
800
- return paramResult;
801
- }
802
- if (schema.type === "string" ||
803
- schema.type === "integer" ||
804
- schema.type === "boolean" ||
805
- schema.type === "number") {
806
- if (isRequiredWithoutDefault) {
807
- paramResult.requiredNum = paramResult.requiredNum + 1;
808
- }
809
- else {
810
- paramResult.optionalNum = paramResult.optionalNum + 1;
811
- }
812
- }
813
- else if (schema.type === "object") {
814
- const { properties } = schema;
815
- for (const property in properties) {
816
- let isRequired = false;
817
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
818
- isRequired = true;
819
- }
820
- const result = this.checkPostBodySchema(properties[property], isRequired);
821
- paramResult.requiredNum += result.requiredNum;
822
- paramResult.optionalNum += result.optionalNum;
823
- paramResult.isValid = paramResult.isValid && result.isValid;
824
- paramResult.reason.push(...result.reason);
825
- }
826
- }
827
- else {
828
- if (isRequiredWithoutDefault && !isCopilot) {
829
- paramResult.isValid = false;
830
- paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
831
- }
832
- }
833
- return paramResult;
834
- }
835
- checkParamSchema(paramObject) {
836
- const paramResult = {
837
- requiredNum: 0,
838
- optionalNum: 0,
839
- isValid: true,
840
- reason: [],
841
- };
842
- if (!paramObject) {
843
- return paramResult;
844
- }
845
- const isCopilot = this.projectType === ProjectType.Copilot;
846
- for (let i = 0; i < paramObject.length; i++) {
847
- const param = paramObject[i];
848
- const schema = param.schema;
849
- if (isCopilot && this.hasNestedObjectInSchema(schema)) {
850
- paramResult.isValid = false;
851
- paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
852
- continue;
853
- }
854
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
855
- if (isCopilot) {
856
- if (isRequiredWithoutDefault) {
857
- paramResult.requiredNum = paramResult.requiredNum + 1;
858
- }
859
- else {
860
- paramResult.optionalNum = paramResult.optionalNum + 1;
861
- }
862
- continue;
863
- }
864
- if (param.in === "header" || param.in === "cookie") {
865
- if (isRequiredWithoutDefault) {
866
- paramResult.isValid = false;
867
- paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
868
- }
869
- continue;
870
- }
871
- if (schema.type !== "boolean" &&
872
- schema.type !== "string" &&
873
- schema.type !== "number" &&
874
- schema.type !== "integer") {
875
- if (isRequiredWithoutDefault) {
876
- paramResult.isValid = false;
877
- paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
878
- }
879
- continue;
880
- }
881
- if (param.in === "query" || param.in === "path") {
882
- if (isRequiredWithoutDefault) {
883
- paramResult.requiredNum = paramResult.requiredNum + 1;
884
- }
885
- else {
886
- paramResult.optionalNum = paramResult.optionalNum + 1;
887
- }
888
- }
889
- }
890
- return paramResult;
891
- }
892
- hasNestedObjectInSchema(schema) {
893
- if (schema.type === "object") {
894
- for (const property in schema.properties) {
895
- const nestedSchema = schema.properties[property];
896
- if (nestedSchema.type === "object") {
897
- return true;
898
- }
899
- }
900
- }
901
- return false;
902
- }
903
779
  }
904
780
 
905
781
  // Copyright (c) Microsoft Corporation.
@@ -909,7 +785,6 @@ class CopilotValidator extends Validator {
909
785
  this.projectType = ProjectType.Copilot;
910
786
  this.options = options;
911
787
  this.spec = spec;
912
- this.checkCircularReference();
913
788
  }
914
789
  validateSpec() {
915
790
  const result = { errors: [], warnings: [] };
@@ -935,10 +810,6 @@ class CopilotValidator extends Validator {
935
810
  if (!methodAndPathResult.isValid) {
936
811
  return methodAndPathResult;
937
812
  }
938
- const circularReferenceResult = this.validateCircularReference(method, path);
939
- if (!circularReferenceResult.isValid) {
940
- return circularReferenceResult;
941
- }
942
813
  const operationObject = this.spec.paths[path][method];
943
814
  // validate auth
944
815
  const authCheckResult = this.validateAuth(method, path);
@@ -950,24 +821,6 @@ class CopilotValidator extends Validator {
950
821
  // validate server
951
822
  const validateServerResult = this.validateServer(method, path);
952
823
  result.reason.push(...validateServerResult.reason);
953
- // validate response
954
- const validateResponseResult = this.validateResponse(method, path);
955
- result.reason.push(...validateResponseResult.reason);
956
- // validate requestBody
957
- const requestBody = operationObject.requestBody;
958
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
959
- if (requestJsonBody) {
960
- const requestBodySchema = requestJsonBody.schema;
961
- if (requestBodySchema.type !== "object") {
962
- result.reason.push(ErrorType.PostBodySchemaIsNotJson);
963
- }
964
- const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
965
- result.reason.push(...requestBodyParamResult.reason);
966
- }
967
- // validate parameters
968
- const paramObject = operationObject.parameters;
969
- const paramResult = this.checkParamSchema(paramObject);
970
- result.reason.push(...paramResult.reason);
971
824
  if (result.reason.length > 0) {
972
825
  result.isValid = false;
973
826
  }
@@ -1059,6 +912,108 @@ class SMEValidator extends Validator {
1059
912
  }
1060
913
  return result;
1061
914
  }
915
+ validateResponse(method, path) {
916
+ const result = { isValid: true, reason: [] };
917
+ const operationObject = this.spec.paths[path][method];
918
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
919
+ // only support response body only contains “application/json” content type
920
+ if (multipleMediaType) {
921
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
922
+ }
923
+ else if (Object.keys(json).length === 0) {
924
+ // response body should not be empty
925
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
926
+ }
927
+ return result;
928
+ }
929
+ checkPostBodySchema(schema, isRequired = false) {
930
+ var _a;
931
+ const paramResult = {
932
+ requiredNum: 0,
933
+ optionalNum: 0,
934
+ isValid: true,
935
+ reason: [],
936
+ };
937
+ if (Object.keys(schema).length === 0) {
938
+ return paramResult;
939
+ }
940
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
941
+ const isCopilot = this.projectType === ProjectType.Copilot;
942
+ if (schema.type === "string" ||
943
+ schema.type === "integer" ||
944
+ schema.type === "boolean" ||
945
+ schema.type === "number") {
946
+ if (isRequiredWithoutDefault) {
947
+ paramResult.requiredNum = paramResult.requiredNum + 1;
948
+ }
949
+ else {
950
+ paramResult.optionalNum = paramResult.optionalNum + 1;
951
+ }
952
+ }
953
+ else if (Utils.isObjectSchema(schema)) {
954
+ const { properties } = schema;
955
+ for (const property in properties) {
956
+ let isRequired = false;
957
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
958
+ isRequired = true;
959
+ }
960
+ const result = this.checkPostBodySchema(properties[property], isRequired);
961
+ paramResult.requiredNum += result.requiredNum;
962
+ paramResult.optionalNum += result.optionalNum;
963
+ paramResult.isValid = paramResult.isValid && result.isValid;
964
+ paramResult.reason.push(...result.reason);
965
+ }
966
+ }
967
+ else {
968
+ if (isRequiredWithoutDefault && !isCopilot) {
969
+ paramResult.isValid = false;
970
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
971
+ }
972
+ }
973
+ return paramResult;
974
+ }
975
+ checkParamSchema(paramObject) {
976
+ const paramResult = {
977
+ requiredNum: 0,
978
+ optionalNum: 0,
979
+ isValid: true,
980
+ reason: [],
981
+ };
982
+ if (!paramObject) {
983
+ return paramResult;
984
+ }
985
+ for (let i = 0; i < paramObject.length; i++) {
986
+ const param = paramObject[i];
987
+ const schema = param.schema;
988
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
989
+ if (param.in === "header" || param.in === "cookie") {
990
+ if (isRequiredWithoutDefault) {
991
+ paramResult.isValid = false;
992
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
993
+ }
994
+ continue;
995
+ }
996
+ if (schema.type !== "boolean" &&
997
+ schema.type !== "string" &&
998
+ schema.type !== "number" &&
999
+ schema.type !== "integer") {
1000
+ if (isRequiredWithoutDefault) {
1001
+ paramResult.isValid = false;
1002
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
1003
+ }
1004
+ continue;
1005
+ }
1006
+ if (param.in === "query" || param.in === "path") {
1007
+ if (isRequiredWithoutDefault) {
1008
+ paramResult.requiredNum = paramResult.requiredNum + 1;
1009
+ }
1010
+ else {
1011
+ paramResult.optionalNum = paramResult.optionalNum + 1;
1012
+ }
1013
+ }
1014
+ }
1015
+ return paramResult;
1016
+ }
1062
1017
  validateParamCount(postBodyResult, paramResult) {
1063
1018
  const result = { isValid: true, reason: [] };
1064
1019
  const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
@@ -1348,20 +1303,157 @@ class SpecParser {
1348
1303
  }
1349
1304
  }
1350
1305
 
1306
+ // Copyright (c) Microsoft Corporation.
1307
+ class JsonDataGenerator {
1308
+ static generate(schema) {
1309
+ return this.generateMockData(schema);
1310
+ }
1311
+ static generateMockData(schema) {
1312
+ if (this.visitedSchemas.has(schema)) {
1313
+ return null; // Prevent circular reference
1314
+ }
1315
+ this.visitedSchemas.add(schema);
1316
+ let result;
1317
+ if (schema.anyOf) {
1318
+ // Select the first schema in anyOf
1319
+ const selectedSchema = schema.anyOf[0];
1320
+ result = this.generateMockData(selectedSchema);
1321
+ }
1322
+ else if (schema.oneOf) {
1323
+ // Select the first schema in oneOf
1324
+ const selectedSchema = schema.oneOf[0];
1325
+ result = this.generateMockData(selectedSchema);
1326
+ }
1327
+ else if (schema.allOf) {
1328
+ // merge all schemas in allOf
1329
+ result = {};
1330
+ for (const subschema of schema.allOf) {
1331
+ const data = this.generateMockData(subschema);
1332
+ result = Object.assign(Object.assign({}, result), data);
1333
+ }
1334
+ }
1335
+ else {
1336
+ switch (schema.type) {
1337
+ case "string":
1338
+ if (schema.example !== undefined) {
1339
+ result = schema.example;
1340
+ }
1341
+ else if (schema.format) {
1342
+ switch (schema.format) {
1343
+ case "date-time":
1344
+ result = "2024-11-01T05:25:43.593Z";
1345
+ break;
1346
+ case "email":
1347
+ result = "example@example.com";
1348
+ break;
1349
+ case "uuid":
1350
+ result = "123e4567-e89b-12d3-a456-426614174000";
1351
+ break;
1352
+ case "ipv4":
1353
+ result = "192.168.0.1";
1354
+ break;
1355
+ case "ipv6":
1356
+ result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
1357
+ break;
1358
+ default:
1359
+ result = "example string";
1360
+ }
1361
+ }
1362
+ else {
1363
+ result = "example string";
1364
+ }
1365
+ break;
1366
+ case "number":
1367
+ if (schema.example !== undefined) {
1368
+ result = schema.example;
1369
+ }
1370
+ else if (schema.format) {
1371
+ switch (schema.format) {
1372
+ case "float":
1373
+ result = 3.14;
1374
+ break;
1375
+ case "double":
1376
+ result = 3.14159;
1377
+ break;
1378
+ default:
1379
+ result = 123;
1380
+ }
1381
+ }
1382
+ else {
1383
+ result = 123;
1384
+ }
1385
+ break;
1386
+ case "integer":
1387
+ if (schema.example !== undefined) {
1388
+ result = schema.example;
1389
+ }
1390
+ else if (schema.format) {
1391
+ switch (schema.format) {
1392
+ case "int32":
1393
+ result = 123456;
1394
+ break;
1395
+ case "int64":
1396
+ result = 123456789;
1397
+ break;
1398
+ default:
1399
+ result = 123;
1400
+ }
1401
+ }
1402
+ else {
1403
+ result = 123;
1404
+ }
1405
+ break;
1406
+ case "boolean":
1407
+ result = schema.example !== undefined ? schema.example : true;
1408
+ break;
1409
+ case "array":
1410
+ result = [this.generateMockData(schema.items)];
1411
+ break;
1412
+ case "object":
1413
+ result = {};
1414
+ if (schema.properties) {
1415
+ for (const key in schema.properties) {
1416
+ result[key] = this.generateMockData(schema.properties[key]);
1417
+ }
1418
+ }
1419
+ break;
1420
+ default:
1421
+ result = schema.example || null;
1422
+ }
1423
+ }
1424
+ this.visitedSchemas.delete(schema);
1425
+ return result;
1426
+ }
1427
+ }
1428
+ JsonDataGenerator.visitedSchemas = new Set();
1429
+
1351
1430
  // Copyright (c) Microsoft Corporation.
1352
1431
  class AdaptiveCardGenerator {
1353
- static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
1432
+ static generateAdaptiveCard(operationItem, allowMultipleMediaType = false, maxElementCount = Number.MAX_SAFE_INTEGER) {
1354
1433
  try {
1355
1434
  const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
1356
1435
  let cardBody = [];
1436
+ let jsonData = {};
1437
+ const warnings = [];
1438
+ const operationId = operationItem.operationId;
1357
1439
  let schema = json.schema;
1358
1440
  let jsonPath = "$";
1359
1441
  if (schema && Object.keys(schema).length > 0) {
1442
+ try {
1443
+ jsonData = JsonDataGenerator.generate(schema);
1444
+ }
1445
+ catch (err) {
1446
+ warnings.push({
1447
+ type: WarningType.GenerateJsonDataFailed,
1448
+ content: Utils.format(ConstantString.GenerateJsonDataFailed, operationId, err.toString()),
1449
+ data: operationId,
1450
+ });
1451
+ }
1360
1452
  jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
1361
1453
  if (jsonPath !== "$") {
1362
1454
  schema = schema.properties[jsonPath];
1363
1455
  }
1364
- cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
1456
+ cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "", "", maxElementCount);
1365
1457
  }
1366
1458
  // if no schema, try to use example value
1367
1459
  if (cardBody.length === 0 && (json.examples || json.example)) {
@@ -1389,16 +1481,20 @@ class AdaptiveCardGenerator {
1389
1481
  version: ConstantString.AdaptiveCardVersion,
1390
1482
  body: cardBody,
1391
1483
  };
1392
- return [fullCard, jsonPath];
1484
+ return [fullCard, jsonPath, jsonData, warnings];
1393
1485
  }
1394
1486
  catch (err) {
1395
1487
  throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
1396
1488
  }
1397
1489
  }
1398
- static generateCardFromResponse(schema, name, parentArrayName = "") {
1490
+ static generateCardFromResponse(schema, name, parentArrayName = "", maxElementCount = Number.MAX_SAFE_INTEGER, counter = { count: 0 }) {
1491
+ if (counter.count >= maxElementCount) {
1492
+ return [];
1493
+ }
1399
1494
  if (schema.type === "array") {
1400
1495
  // schema.items can be arbitrary object: schema { type: array, items: {} }
1401
1496
  if (Object.keys(schema.items).length === 0) {
1497
+ counter.count++;
1402
1498
  return [
1403
1499
  {
1404
1500
  type: ConstantString.TextBlockType,
@@ -1407,7 +1503,7 @@ class AdaptiveCardGenerator {
1407
1503
  },
1408
1504
  ];
1409
1505
  }
1410
- const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
1506
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name, maxElementCount, counter);
1411
1507
  const template = {
1412
1508
  type: ConstantString.ContainerType,
1413
1509
  $data: name ? `\${${name}}` : "${$root}",
@@ -1417,11 +1513,11 @@ class AdaptiveCardGenerator {
1417
1513
  return [template];
1418
1514
  }
1419
1515
  // some schema may not contain type but contain properties
1420
- if (schema.type === "object" || (!schema.type && schema.properties)) {
1516
+ if (Utils.isObjectSchema(schema)) {
1421
1517
  const { properties } = schema;
1422
1518
  const result = [];
1423
1519
  for (const property in properties) {
1424
- const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
1520
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName, maxElementCount, counter);
1425
1521
  result.push(...obj);
1426
1522
  }
1427
1523
  if (schema.additionalProperties) {
@@ -1434,6 +1530,7 @@ class AdaptiveCardGenerator {
1434
1530
  schema.type === "integer" ||
1435
1531
  schema.type === "boolean" ||
1436
1532
  schema.type === "number") {
1533
+ counter.count++;
1437
1534
  if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
1438
1535
  // string in root: "ddd"
1439
1536
  let text = "result: ${$root}";
@@ -1458,24 +1555,17 @@ class AdaptiveCardGenerator {
1458
1555
  ];
1459
1556
  }
1460
1557
  else {
1461
- if (name) {
1462
- return [
1463
- {
1464
- type: "Image",
1465
- url: `\${${name}}`,
1466
- $when: `\${${name} != null && ${name} != ''}`,
1467
- },
1468
- ];
1469
- }
1470
- else {
1471
- return [
1472
- {
1473
- type: "Image",
1474
- url: "${$data}",
1475
- $when: "${$data != null && $data != ''}",
1476
- },
1477
- ];
1478
- }
1558
+ const url = name ? `\${${name}}` : "${$data}";
1559
+ const condition = name
1560
+ ? `\${${name} != null && ${name} != ''}`
1561
+ : "${$data != null && $data != ''}";
1562
+ return [
1563
+ {
1564
+ type: "Image",
1565
+ url,
1566
+ $when: condition,
1567
+ },
1568
+ ];
1479
1569
  }
1480
1570
  }
1481
1571
  if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
@@ -1485,7 +1575,7 @@ class AdaptiveCardGenerator {
1485
1575
  }
1486
1576
  // Find the first array property in the response schema object with the well-known name
1487
1577
  static getResponseJsonPathFromSchema(schema) {
1488
- if (schema.type === "object" || (!schema.type && schema.properties)) {
1578
+ if (Utils.isObjectSchema(schema)) {
1489
1579
  const { properties } = schema;
1490
1580
  for (const property in properties) {
1491
1581
  const schema = properties[property];