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