@microsoft/m365-spec-parser 0.2.3 → 0.2.4-rc-hotfix.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.
- package/dist/index.esm2017.js +302 -242
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +355 -277
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +302 -242
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +355 -277
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/adaptiveCardGenerator.d.ts +5 -3
- package/dist/src/constants.d.ts +3 -1
- package/dist/src/interfaces.d.ts +2 -3
- package/dist/src/jsonDataGenerator.d.ts +6 -0
- package/dist/src/utils.d.ts +4 -4
- package/package.json +3 -3
package/dist/index.esm5.js
CHANGED
|
@@ -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,8 @@ 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["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
88
87
|
WarningType["Unknown"] = "unknown";
|
|
89
88
|
})(WarningType || (WarningType = {}));
|
|
90
89
|
/**
|
|
@@ -130,15 +129,17 @@ ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converte
|
|
|
130
129
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
131
130
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
132
131
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
132
|
+
ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
|
|
133
133
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
134
134
|
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.";
|
|
135
|
+
ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
|
|
135
136
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
136
137
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
137
138
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
138
139
|
ConstantString.GetMethod = "get";
|
|
139
140
|
ConstantString.PostMethod = "post";
|
|
140
141
|
ConstantString.AdaptiveCardVersion = "1.5";
|
|
141
|
-
ConstantString.AdaptiveCardSchema = "
|
|
142
|
+
ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
|
|
142
143
|
ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
143
144
|
ConstantString.TextBlockType = "TextBlock";
|
|
144
145
|
ConstantString.ImageType = "Image";
|
|
@@ -217,16 +218,8 @@ ConstantString.PluginManifestSchema = "https://developer.microsoft.com/json-sche
|
|
|
217
218
|
|
|
218
219
|
// Copyright (c) Microsoft Corporation.
|
|
219
220
|
class Utils {
|
|
220
|
-
static
|
|
221
|
-
|
|
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;
|
|
221
|
+
static isObjectSchema(schema) {
|
|
222
|
+
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
230
223
|
}
|
|
231
224
|
static containMultipleMediaTypes(bodyObject) {
|
|
232
225
|
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
@@ -294,27 +287,33 @@ class Utils {
|
|
|
294
287
|
let multipleMediaType = false;
|
|
295
288
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
296
289
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
297
|
-
if (responseObject
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
else {
|
|
310
|
-
return { json, multipleMediaType };
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
290
|
+
if (!responseObject) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
|
|
294
|
+
if (!allowMultipleMediaType && multipleMediaType) {
|
|
295
|
+
json = {};
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const mediaObj = Utils.getJsonContentType(responseObject);
|
|
299
|
+
if (Object.keys(mediaObj).length > 0) {
|
|
300
|
+
json = mediaObj;
|
|
301
|
+
return { json, multipleMediaType };
|
|
314
302
|
}
|
|
315
303
|
}
|
|
316
304
|
return { json, multipleMediaType };
|
|
317
305
|
}
|
|
306
|
+
static getJsonContentType(responseObject) {
|
|
307
|
+
if (responseObject.content) {
|
|
308
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
309
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
310
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
311
|
+
return responseObject.content[contentType];
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return {};
|
|
316
|
+
}
|
|
318
317
|
static convertPathToCamelCase(path) {
|
|
319
318
|
const pathSegments = path.split(/[./{]/);
|
|
320
319
|
const camelCaseSegments = pathSegments.map((segment) => {
|
|
@@ -350,7 +349,7 @@ class Utils {
|
|
|
350
349
|
}
|
|
351
350
|
return newStr;
|
|
352
351
|
}
|
|
353
|
-
static checkServerUrl(servers) {
|
|
352
|
+
static checkServerUrl(servers, allowHttp = false) {
|
|
354
353
|
const errors = [];
|
|
355
354
|
let serverUrl;
|
|
356
355
|
try {
|
|
@@ -373,8 +372,7 @@ class Utils {
|
|
|
373
372
|
data: servers,
|
|
374
373
|
});
|
|
375
374
|
}
|
|
376
|
-
else if (protocol !== "https:") {
|
|
377
|
-
// Http server url is not supported
|
|
375
|
+
else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
|
|
378
376
|
const protocolString = protocol.slice(0, -1);
|
|
379
377
|
errors.push({
|
|
380
378
|
type: ErrorType.UrlProtocolNotSupported,
|
|
@@ -390,10 +388,11 @@ class Utils {
|
|
|
390
388
|
let hasTopLevelServers = false;
|
|
391
389
|
let hasPathLevelServers = false;
|
|
392
390
|
let hasOperationLevelServers = false;
|
|
391
|
+
const allowHttp = options.projectType === ProjectType.Copilot;
|
|
393
392
|
if (spec.servers && spec.servers.length >= 1) {
|
|
394
393
|
hasTopLevelServers = true;
|
|
395
394
|
// for multiple server, we only use the first url
|
|
396
|
-
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
395
|
+
const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
|
|
397
396
|
errors.push(...serverErrors);
|
|
398
397
|
}
|
|
399
398
|
const paths = spec.paths;
|
|
@@ -401,7 +400,7 @@ class Utils {
|
|
|
401
400
|
const methods = paths[path];
|
|
402
401
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
403
402
|
hasPathLevelServers = true;
|
|
404
|
-
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
403
|
+
const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
|
|
405
404
|
errors.push(...serverErrors);
|
|
406
405
|
}
|
|
407
406
|
for (const method in methods) {
|
|
@@ -409,7 +408,7 @@ class Utils {
|
|
|
409
408
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
410
409
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
411
410
|
hasOperationLevelServers = true;
|
|
412
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
411
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
|
|
413
412
|
errors.push(...serverErrors);
|
|
414
413
|
}
|
|
415
414
|
}
|
|
@@ -456,7 +455,7 @@ class Utils {
|
|
|
456
455
|
optionalParams.push(parameter);
|
|
457
456
|
}
|
|
458
457
|
}
|
|
459
|
-
else if (schema
|
|
458
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
460
459
|
const { properties } = schema;
|
|
461
460
|
for (const property in properties) {
|
|
462
461
|
let isRequired = false;
|
|
@@ -570,29 +569,6 @@ class Utils {
|
|
|
570
569
|
const serverUrl = operationServer || methodServer || rootServer;
|
|
571
570
|
return serverUrl;
|
|
572
571
|
}
|
|
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
572
|
}
|
|
597
573
|
|
|
598
574
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -721,22 +697,6 @@ class Validator {
|
|
|
721
697
|
}
|
|
722
698
|
return result;
|
|
723
699
|
}
|
|
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
700
|
validateServer(method, path) {
|
|
741
701
|
const result = { isValid: true, reason: [] };
|
|
742
702
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -745,8 +705,8 @@ class Validator {
|
|
|
745
705
|
result.reason.push(ErrorType.NoServerInformation);
|
|
746
706
|
}
|
|
747
707
|
else {
|
|
748
|
-
|
|
749
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
708
|
+
const allowHttp = this.projectType === ProjectType.Copilot;
|
|
709
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
|
|
750
710
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
751
711
|
}
|
|
752
712
|
return result;
|
|
@@ -781,125 +741,6 @@ class Validator {
|
|
|
781
741
|
}
|
|
782
742
|
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
783
743
|
}
|
|
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
744
|
}
|
|
904
745
|
|
|
905
746
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -950,24 +791,6 @@ class CopilotValidator extends Validator {
|
|
|
950
791
|
// validate server
|
|
951
792
|
const validateServerResult = this.validateServer(method, path);
|
|
952
793
|
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
794
|
if (result.reason.length > 0) {
|
|
972
795
|
result.isValid = false;
|
|
973
796
|
}
|
|
@@ -1059,6 +882,108 @@ class SMEValidator extends Validator {
|
|
|
1059
882
|
}
|
|
1060
883
|
return result;
|
|
1061
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
|
+
}
|
|
1062
987
|
validateParamCount(postBodyResult, paramResult) {
|
|
1063
988
|
const result = { isValid: true, reason: [] };
|
|
1064
989
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
@@ -1348,20 +1273,157 @@ class SpecParser {
|
|
|
1348
1273
|
}
|
|
1349
1274
|
}
|
|
1350
1275
|
|
|
1276
|
+
// Copyright (c) Microsoft Corporation.
|
|
1277
|
+
class JsonDataGenerator {
|
|
1278
|
+
static generate(schema) {
|
|
1279
|
+
return this.generateMockData(schema);
|
|
1280
|
+
}
|
|
1281
|
+
static generateMockData(schema) {
|
|
1282
|
+
if (this.visitedSchemas.has(schema)) {
|
|
1283
|
+
return null; // Prevent circular reference
|
|
1284
|
+
}
|
|
1285
|
+
this.visitedSchemas.add(schema);
|
|
1286
|
+
let result;
|
|
1287
|
+
if (schema.anyOf) {
|
|
1288
|
+
// Select the first schema in anyOf
|
|
1289
|
+
const selectedSchema = schema.anyOf[0];
|
|
1290
|
+
result = this.generateMockData(selectedSchema);
|
|
1291
|
+
}
|
|
1292
|
+
else if (schema.oneOf) {
|
|
1293
|
+
// Select the first schema in oneOf
|
|
1294
|
+
const selectedSchema = schema.oneOf[0];
|
|
1295
|
+
result = this.generateMockData(selectedSchema);
|
|
1296
|
+
}
|
|
1297
|
+
else if (schema.allOf) {
|
|
1298
|
+
// merge all schemas in allOf
|
|
1299
|
+
result = {};
|
|
1300
|
+
for (const subschema of schema.allOf) {
|
|
1301
|
+
const data = this.generateMockData(subschema);
|
|
1302
|
+
result = Object.assign(Object.assign({}, result), data);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
else {
|
|
1306
|
+
switch (schema.type) {
|
|
1307
|
+
case "string":
|
|
1308
|
+
if (schema.example !== undefined) {
|
|
1309
|
+
result = schema.example;
|
|
1310
|
+
}
|
|
1311
|
+
else if (schema.format) {
|
|
1312
|
+
switch (schema.format) {
|
|
1313
|
+
case "date-time":
|
|
1314
|
+
result = "2024-11-01T05:25:43.593Z";
|
|
1315
|
+
break;
|
|
1316
|
+
case "email":
|
|
1317
|
+
result = "example@example.com";
|
|
1318
|
+
break;
|
|
1319
|
+
case "uuid":
|
|
1320
|
+
result = "123e4567-e89b-12d3-a456-426614174000";
|
|
1321
|
+
break;
|
|
1322
|
+
case "ipv4":
|
|
1323
|
+
result = "192.168.0.1";
|
|
1324
|
+
break;
|
|
1325
|
+
case "ipv6":
|
|
1326
|
+
result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
|
|
1327
|
+
break;
|
|
1328
|
+
default:
|
|
1329
|
+
result = "example string";
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
else {
|
|
1333
|
+
result = "example string";
|
|
1334
|
+
}
|
|
1335
|
+
break;
|
|
1336
|
+
case "number":
|
|
1337
|
+
if (schema.example !== undefined) {
|
|
1338
|
+
result = schema.example;
|
|
1339
|
+
}
|
|
1340
|
+
else if (schema.format) {
|
|
1341
|
+
switch (schema.format) {
|
|
1342
|
+
case "float":
|
|
1343
|
+
result = 3.14;
|
|
1344
|
+
break;
|
|
1345
|
+
case "double":
|
|
1346
|
+
result = 3.14159;
|
|
1347
|
+
break;
|
|
1348
|
+
default:
|
|
1349
|
+
result = 123;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
else {
|
|
1353
|
+
result = 123;
|
|
1354
|
+
}
|
|
1355
|
+
break;
|
|
1356
|
+
case "integer":
|
|
1357
|
+
if (schema.example !== undefined) {
|
|
1358
|
+
result = schema.example;
|
|
1359
|
+
}
|
|
1360
|
+
else if (schema.format) {
|
|
1361
|
+
switch (schema.format) {
|
|
1362
|
+
case "int32":
|
|
1363
|
+
result = 123456;
|
|
1364
|
+
break;
|
|
1365
|
+
case "int64":
|
|
1366
|
+
result = 123456789;
|
|
1367
|
+
break;
|
|
1368
|
+
default:
|
|
1369
|
+
result = 123;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
else {
|
|
1373
|
+
result = 123;
|
|
1374
|
+
}
|
|
1375
|
+
break;
|
|
1376
|
+
case "boolean":
|
|
1377
|
+
result = schema.example !== undefined ? schema.example : true;
|
|
1378
|
+
break;
|
|
1379
|
+
case "array":
|
|
1380
|
+
result = [this.generateMockData(schema.items)];
|
|
1381
|
+
break;
|
|
1382
|
+
case "object":
|
|
1383
|
+
result = {};
|
|
1384
|
+
if (schema.properties) {
|
|
1385
|
+
for (const key in schema.properties) {
|
|
1386
|
+
result[key] = this.generateMockData(schema.properties[key]);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
break;
|
|
1390
|
+
default:
|
|
1391
|
+
result = schema.example || null;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
this.visitedSchemas.delete(schema);
|
|
1395
|
+
return result;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
JsonDataGenerator.visitedSchemas = new Set();
|
|
1399
|
+
|
|
1351
1400
|
// Copyright (c) Microsoft Corporation.
|
|
1352
1401
|
class AdaptiveCardGenerator {
|
|
1353
|
-
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
|
|
1402
|
+
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false, maxElementCount = Number.MAX_SAFE_INTEGER) {
|
|
1354
1403
|
try {
|
|
1355
1404
|
const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
|
|
1356
1405
|
let cardBody = [];
|
|
1406
|
+
let jsonData = {};
|
|
1407
|
+
const warnings = [];
|
|
1408
|
+
const operationId = operationItem.operationId;
|
|
1357
1409
|
let schema = json.schema;
|
|
1358
1410
|
let jsonPath = "$";
|
|
1359
1411
|
if (schema && Object.keys(schema).length > 0) {
|
|
1412
|
+
try {
|
|
1413
|
+
jsonData = JsonDataGenerator.generate(schema);
|
|
1414
|
+
}
|
|
1415
|
+
catch (err) {
|
|
1416
|
+
warnings.push({
|
|
1417
|
+
type: WarningType.GenerateJsonDataFailed,
|
|
1418
|
+
content: Utils.format(ConstantString.GenerateJsonDataFailed, operationId, err.toString()),
|
|
1419
|
+
data: operationId,
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1360
1422
|
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
1361
1423
|
if (jsonPath !== "$") {
|
|
1362
1424
|
schema = schema.properties[jsonPath];
|
|
1363
1425
|
}
|
|
1364
|
-
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
1426
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "", "", maxElementCount);
|
|
1365
1427
|
}
|
|
1366
1428
|
// if no schema, try to use example value
|
|
1367
1429
|
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
@@ -1389,16 +1451,20 @@ class AdaptiveCardGenerator {
|
|
|
1389
1451
|
version: ConstantString.AdaptiveCardVersion,
|
|
1390
1452
|
body: cardBody,
|
|
1391
1453
|
};
|
|
1392
|
-
return [fullCard, jsonPath];
|
|
1454
|
+
return [fullCard, jsonPath, jsonData, warnings];
|
|
1393
1455
|
}
|
|
1394
1456
|
catch (err) {
|
|
1395
1457
|
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
1396
1458
|
}
|
|
1397
1459
|
}
|
|
1398
|
-
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
1460
|
+
static generateCardFromResponse(schema, name, parentArrayName = "", maxElementCount = Number.MAX_SAFE_INTEGER, counter = { count: 0 }) {
|
|
1461
|
+
if (counter.count >= maxElementCount) {
|
|
1462
|
+
return [];
|
|
1463
|
+
}
|
|
1399
1464
|
if (schema.type === "array") {
|
|
1400
1465
|
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
1401
1466
|
if (Object.keys(schema.items).length === 0) {
|
|
1467
|
+
counter.count++;
|
|
1402
1468
|
return [
|
|
1403
1469
|
{
|
|
1404
1470
|
type: ConstantString.TextBlockType,
|
|
@@ -1407,7 +1473,7 @@ class AdaptiveCardGenerator {
|
|
|
1407
1473
|
},
|
|
1408
1474
|
];
|
|
1409
1475
|
}
|
|
1410
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
1476
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name, maxElementCount, counter);
|
|
1411
1477
|
const template = {
|
|
1412
1478
|
type: ConstantString.ContainerType,
|
|
1413
1479
|
$data: name ? `\${${name}}` : "${$root}",
|
|
@@ -1417,11 +1483,11 @@ class AdaptiveCardGenerator {
|
|
|
1417
1483
|
return [template];
|
|
1418
1484
|
}
|
|
1419
1485
|
// some schema may not contain type but contain properties
|
|
1420
|
-
if (
|
|
1486
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1421
1487
|
const { properties } = schema;
|
|
1422
1488
|
const result = [];
|
|
1423
1489
|
for (const property in properties) {
|
|
1424
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
1490
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName, maxElementCount, counter);
|
|
1425
1491
|
result.push(...obj);
|
|
1426
1492
|
}
|
|
1427
1493
|
if (schema.additionalProperties) {
|
|
@@ -1434,6 +1500,7 @@ class AdaptiveCardGenerator {
|
|
|
1434
1500
|
schema.type === "integer" ||
|
|
1435
1501
|
schema.type === "boolean" ||
|
|
1436
1502
|
schema.type === "number") {
|
|
1503
|
+
counter.count++;
|
|
1437
1504
|
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1438
1505
|
// string in root: "ddd"
|
|
1439
1506
|
let text = "result: ${$root}";
|
|
@@ -1458,24 +1525,17 @@ class AdaptiveCardGenerator {
|
|
|
1458
1525
|
];
|
|
1459
1526
|
}
|
|
1460
1527
|
else {
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
{
|
|
1473
|
-
type: "Image",
|
|
1474
|
-
url: "${$data}",
|
|
1475
|
-
$when: "${$data != null && $data != ''}",
|
|
1476
|
-
},
|
|
1477
|
-
];
|
|
1478
|
-
}
|
|
1528
|
+
const url = name ? `\${${name}}` : "${$data}";
|
|
1529
|
+
const condition = name
|
|
1530
|
+
? `\${${name} != null && ${name} != ''}`
|
|
1531
|
+
: "${$data != null && $data != ''}";
|
|
1532
|
+
return [
|
|
1533
|
+
{
|
|
1534
|
+
type: "Image",
|
|
1535
|
+
url,
|
|
1536
|
+
$when: condition,
|
|
1537
|
+
},
|
|
1538
|
+
];
|
|
1479
1539
|
}
|
|
1480
1540
|
}
|
|
1481
1541
|
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
@@ -1485,7 +1545,7 @@ class AdaptiveCardGenerator {
|
|
|
1485
1545
|
}
|
|
1486
1546
|
// Find the first array property in the response schema object with the well-known name
|
|
1487
1547
|
static getResponseJsonPathFromSchema(schema) {
|
|
1488
|
-
if (
|
|
1548
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1489
1549
|
const { properties } = schema;
|
|
1490
1550
|
for (const property in properties) {
|
|
1491
1551
|
const schema = properties[property];
|