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