@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.esm2017.js
CHANGED
|
@@ -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,8 @@ 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["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
58
57
|
WarningType["Unknown"] = "unknown";
|
|
59
58
|
})(WarningType || (WarningType = {}));
|
|
60
59
|
/**
|
|
@@ -100,15 +99,17 @@ ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converte
|
|
|
100
99
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
101
100
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
102
101
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
102
|
+
ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
|
|
103
103
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
104
104
|
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.";
|
|
105
|
+
ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
|
|
105
106
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
106
107
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
107
108
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
108
109
|
ConstantString.GetMethod = "get";
|
|
109
110
|
ConstantString.PostMethod = "post";
|
|
110
111
|
ConstantString.AdaptiveCardVersion = "1.5";
|
|
111
|
-
ConstantString.AdaptiveCardSchema = "
|
|
112
|
+
ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
|
|
112
113
|
ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
113
114
|
ConstantString.TextBlockType = "TextBlock";
|
|
114
115
|
ConstantString.ImageType = "Image";
|
|
@@ -187,16 +188,8 @@ ConstantString.PluginManifestSchema = "https://developer.microsoft.com/json-sche
|
|
|
187
188
|
|
|
188
189
|
// Copyright (c) Microsoft Corporation.
|
|
189
190
|
class Utils {
|
|
190
|
-
static
|
|
191
|
-
|
|
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;
|
|
191
|
+
static isObjectSchema(schema) {
|
|
192
|
+
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
200
193
|
}
|
|
201
194
|
static containMultipleMediaTypes(bodyObject) {
|
|
202
195
|
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
@@ -264,27 +257,33 @@ class Utils {
|
|
|
264
257
|
let multipleMediaType = false;
|
|
265
258
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
266
259
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
267
|
-
if (responseObject
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
else {
|
|
280
|
-
return { json, multipleMediaType };
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
260
|
+
if (!responseObject) {
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
|
|
264
|
+
if (!allowMultipleMediaType && multipleMediaType) {
|
|
265
|
+
json = {};
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const mediaObj = Utils.getJsonContentType(responseObject);
|
|
269
|
+
if (Object.keys(mediaObj).length > 0) {
|
|
270
|
+
json = mediaObj;
|
|
271
|
+
return { json, multipleMediaType };
|
|
284
272
|
}
|
|
285
273
|
}
|
|
286
274
|
return { json, multipleMediaType };
|
|
287
275
|
}
|
|
276
|
+
static getJsonContentType(responseObject) {
|
|
277
|
+
if (responseObject.content) {
|
|
278
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
279
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
280
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
281
|
+
return responseObject.content[contentType];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return {};
|
|
286
|
+
}
|
|
288
287
|
static convertPathToCamelCase(path) {
|
|
289
288
|
const pathSegments = path.split(/[./{]/);
|
|
290
289
|
const camelCaseSegments = pathSegments.map((segment) => {
|
|
@@ -320,7 +319,7 @@ class Utils {
|
|
|
320
319
|
}
|
|
321
320
|
return newStr;
|
|
322
321
|
}
|
|
323
|
-
static checkServerUrl(servers) {
|
|
322
|
+
static checkServerUrl(servers, allowHttp = false) {
|
|
324
323
|
const errors = [];
|
|
325
324
|
let serverUrl;
|
|
326
325
|
try {
|
|
@@ -343,8 +342,7 @@ class Utils {
|
|
|
343
342
|
data: servers,
|
|
344
343
|
});
|
|
345
344
|
}
|
|
346
|
-
else if (protocol !== "https:") {
|
|
347
|
-
// Http server url is not supported
|
|
345
|
+
else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
|
|
348
346
|
const protocolString = protocol.slice(0, -1);
|
|
349
347
|
errors.push({
|
|
350
348
|
type: ErrorType.UrlProtocolNotSupported,
|
|
@@ -360,10 +358,11 @@ class Utils {
|
|
|
360
358
|
let hasTopLevelServers = false;
|
|
361
359
|
let hasPathLevelServers = false;
|
|
362
360
|
let hasOperationLevelServers = false;
|
|
361
|
+
const allowHttp = options.projectType === ProjectType.Copilot;
|
|
363
362
|
if (spec.servers && spec.servers.length >= 1) {
|
|
364
363
|
hasTopLevelServers = true;
|
|
365
364
|
// for multiple server, we only use the first url
|
|
366
|
-
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
365
|
+
const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
|
|
367
366
|
errors.push(...serverErrors);
|
|
368
367
|
}
|
|
369
368
|
const paths = spec.paths;
|
|
@@ -371,7 +370,7 @@ class Utils {
|
|
|
371
370
|
const methods = paths[path];
|
|
372
371
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
373
372
|
hasPathLevelServers = true;
|
|
374
|
-
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
373
|
+
const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
|
|
375
374
|
errors.push(...serverErrors);
|
|
376
375
|
}
|
|
377
376
|
for (const method in methods) {
|
|
@@ -379,7 +378,7 @@ class Utils {
|
|
|
379
378
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
380
379
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
381
380
|
hasOperationLevelServers = true;
|
|
382
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
381
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
|
|
383
382
|
errors.push(...serverErrors);
|
|
384
383
|
}
|
|
385
384
|
}
|
|
@@ -426,7 +425,7 @@ class Utils {
|
|
|
426
425
|
optionalParams.push(parameter);
|
|
427
426
|
}
|
|
428
427
|
}
|
|
429
|
-
else if (schema
|
|
428
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
430
429
|
const { properties } = schema;
|
|
431
430
|
for (const property in properties) {
|
|
432
431
|
let isRequired = false;
|
|
@@ -540,29 +539,6 @@ class Utils {
|
|
|
540
539
|
const serverUrl = operationServer || methodServer || rootServer;
|
|
541
540
|
return serverUrl;
|
|
542
541
|
}
|
|
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
542
|
}
|
|
567
543
|
|
|
568
544
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -691,22 +667,6 @@ class Validator {
|
|
|
691
667
|
}
|
|
692
668
|
return result;
|
|
693
669
|
}
|
|
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
670
|
validateServer(method, path) {
|
|
711
671
|
const result = { isValid: true, reason: [] };
|
|
712
672
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -715,8 +675,8 @@ class Validator {
|
|
|
715
675
|
result.reason.push(ErrorType.NoServerInformation);
|
|
716
676
|
}
|
|
717
677
|
else {
|
|
718
|
-
|
|
719
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
678
|
+
const allowHttp = this.projectType === ProjectType.Copilot;
|
|
679
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
|
|
720
680
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
721
681
|
}
|
|
722
682
|
return result;
|
|
@@ -751,125 +711,6 @@ class Validator {
|
|
|
751
711
|
}
|
|
752
712
|
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
753
713
|
}
|
|
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
714
|
}
|
|
874
715
|
|
|
875
716
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -920,24 +761,6 @@ class CopilotValidator extends Validator {
|
|
|
920
761
|
// validate server
|
|
921
762
|
const validateServerResult = this.validateServer(method, path);
|
|
922
763
|
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
764
|
if (result.reason.length > 0) {
|
|
942
765
|
result.isValid = false;
|
|
943
766
|
}
|
|
@@ -1029,6 +852,108 @@ class SMEValidator extends Validator {
|
|
|
1029
852
|
}
|
|
1030
853
|
return result;
|
|
1031
854
|
}
|
|
855
|
+
validateResponse(method, path) {
|
|
856
|
+
const result = { isValid: true, reason: [] };
|
|
857
|
+
const operationObject = this.spec.paths[path][method];
|
|
858
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
859
|
+
// only support response body only contains “application/json” content type
|
|
860
|
+
if (multipleMediaType) {
|
|
861
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
862
|
+
}
|
|
863
|
+
else if (Object.keys(json).length === 0) {
|
|
864
|
+
// response body should not be empty
|
|
865
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
866
|
+
}
|
|
867
|
+
return result;
|
|
868
|
+
}
|
|
869
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
870
|
+
var _a;
|
|
871
|
+
const paramResult = {
|
|
872
|
+
requiredNum: 0,
|
|
873
|
+
optionalNum: 0,
|
|
874
|
+
isValid: true,
|
|
875
|
+
reason: [],
|
|
876
|
+
};
|
|
877
|
+
if (Object.keys(schema).length === 0) {
|
|
878
|
+
return paramResult;
|
|
879
|
+
}
|
|
880
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
881
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
882
|
+
if (schema.type === "string" ||
|
|
883
|
+
schema.type === "integer" ||
|
|
884
|
+
schema.type === "boolean" ||
|
|
885
|
+
schema.type === "number") {
|
|
886
|
+
if (isRequiredWithoutDefault) {
|
|
887
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
888
|
+
}
|
|
889
|
+
else {
|
|
890
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
894
|
+
const { properties } = schema;
|
|
895
|
+
for (const property in properties) {
|
|
896
|
+
let isRequired = false;
|
|
897
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
898
|
+
isRequired = true;
|
|
899
|
+
}
|
|
900
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
901
|
+
paramResult.requiredNum += result.requiredNum;
|
|
902
|
+
paramResult.optionalNum += result.optionalNum;
|
|
903
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
904
|
+
paramResult.reason.push(...result.reason);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
909
|
+
paramResult.isValid = false;
|
|
910
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
return paramResult;
|
|
914
|
+
}
|
|
915
|
+
checkParamSchema(paramObject) {
|
|
916
|
+
const paramResult = {
|
|
917
|
+
requiredNum: 0,
|
|
918
|
+
optionalNum: 0,
|
|
919
|
+
isValid: true,
|
|
920
|
+
reason: [],
|
|
921
|
+
};
|
|
922
|
+
if (!paramObject) {
|
|
923
|
+
return paramResult;
|
|
924
|
+
}
|
|
925
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
926
|
+
const param = paramObject[i];
|
|
927
|
+
const schema = param.schema;
|
|
928
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
929
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
930
|
+
if (isRequiredWithoutDefault) {
|
|
931
|
+
paramResult.isValid = false;
|
|
932
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
933
|
+
}
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
if (schema.type !== "boolean" &&
|
|
937
|
+
schema.type !== "string" &&
|
|
938
|
+
schema.type !== "number" &&
|
|
939
|
+
schema.type !== "integer") {
|
|
940
|
+
if (isRequiredWithoutDefault) {
|
|
941
|
+
paramResult.isValid = false;
|
|
942
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
943
|
+
}
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
if (param.in === "query" || param.in === "path") {
|
|
947
|
+
if (isRequiredWithoutDefault) {
|
|
948
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
949
|
+
}
|
|
950
|
+
else {
|
|
951
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return paramResult;
|
|
956
|
+
}
|
|
1032
957
|
validateParamCount(postBodyResult, paramResult) {
|
|
1033
958
|
const result = { isValid: true, reason: [] };
|
|
1034
959
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
@@ -1304,20 +1229,157 @@ class SpecParser {
|
|
|
1304
1229
|
}
|
|
1305
1230
|
}
|
|
1306
1231
|
|
|
1232
|
+
// Copyright (c) Microsoft Corporation.
|
|
1233
|
+
class JsonDataGenerator {
|
|
1234
|
+
static generate(schema) {
|
|
1235
|
+
return this.generateMockData(schema);
|
|
1236
|
+
}
|
|
1237
|
+
static generateMockData(schema) {
|
|
1238
|
+
if (this.visitedSchemas.has(schema)) {
|
|
1239
|
+
return null; // Prevent circular reference
|
|
1240
|
+
}
|
|
1241
|
+
this.visitedSchemas.add(schema);
|
|
1242
|
+
let result;
|
|
1243
|
+
if (schema.anyOf) {
|
|
1244
|
+
// Select the first schema in anyOf
|
|
1245
|
+
const selectedSchema = schema.anyOf[0];
|
|
1246
|
+
result = this.generateMockData(selectedSchema);
|
|
1247
|
+
}
|
|
1248
|
+
else if (schema.oneOf) {
|
|
1249
|
+
// Select the first schema in oneOf
|
|
1250
|
+
const selectedSchema = schema.oneOf[0];
|
|
1251
|
+
result = this.generateMockData(selectedSchema);
|
|
1252
|
+
}
|
|
1253
|
+
else if (schema.allOf) {
|
|
1254
|
+
// merge all schemas in allOf
|
|
1255
|
+
result = {};
|
|
1256
|
+
for (const subschema of schema.allOf) {
|
|
1257
|
+
const data = this.generateMockData(subschema);
|
|
1258
|
+
result = Object.assign(Object.assign({}, result), data);
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
else {
|
|
1262
|
+
switch (schema.type) {
|
|
1263
|
+
case "string":
|
|
1264
|
+
if (schema.example !== undefined) {
|
|
1265
|
+
result = schema.example;
|
|
1266
|
+
}
|
|
1267
|
+
else if (schema.format) {
|
|
1268
|
+
switch (schema.format) {
|
|
1269
|
+
case "date-time":
|
|
1270
|
+
result = "2024-11-01T05:25:43.593Z";
|
|
1271
|
+
break;
|
|
1272
|
+
case "email":
|
|
1273
|
+
result = "example@example.com";
|
|
1274
|
+
break;
|
|
1275
|
+
case "uuid":
|
|
1276
|
+
result = "123e4567-e89b-12d3-a456-426614174000";
|
|
1277
|
+
break;
|
|
1278
|
+
case "ipv4":
|
|
1279
|
+
result = "192.168.0.1";
|
|
1280
|
+
break;
|
|
1281
|
+
case "ipv6":
|
|
1282
|
+
result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
|
|
1283
|
+
break;
|
|
1284
|
+
default:
|
|
1285
|
+
result = "example string";
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
else {
|
|
1289
|
+
result = "example string";
|
|
1290
|
+
}
|
|
1291
|
+
break;
|
|
1292
|
+
case "number":
|
|
1293
|
+
if (schema.example !== undefined) {
|
|
1294
|
+
result = schema.example;
|
|
1295
|
+
}
|
|
1296
|
+
else if (schema.format) {
|
|
1297
|
+
switch (schema.format) {
|
|
1298
|
+
case "float":
|
|
1299
|
+
result = 3.14;
|
|
1300
|
+
break;
|
|
1301
|
+
case "double":
|
|
1302
|
+
result = 3.14159;
|
|
1303
|
+
break;
|
|
1304
|
+
default:
|
|
1305
|
+
result = 123;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
else {
|
|
1309
|
+
result = 123;
|
|
1310
|
+
}
|
|
1311
|
+
break;
|
|
1312
|
+
case "integer":
|
|
1313
|
+
if (schema.example !== undefined) {
|
|
1314
|
+
result = schema.example;
|
|
1315
|
+
}
|
|
1316
|
+
else if (schema.format) {
|
|
1317
|
+
switch (schema.format) {
|
|
1318
|
+
case "int32":
|
|
1319
|
+
result = 123456;
|
|
1320
|
+
break;
|
|
1321
|
+
case "int64":
|
|
1322
|
+
result = 123456789;
|
|
1323
|
+
break;
|
|
1324
|
+
default:
|
|
1325
|
+
result = 123;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
else {
|
|
1329
|
+
result = 123;
|
|
1330
|
+
}
|
|
1331
|
+
break;
|
|
1332
|
+
case "boolean":
|
|
1333
|
+
result = schema.example !== undefined ? schema.example : true;
|
|
1334
|
+
break;
|
|
1335
|
+
case "array":
|
|
1336
|
+
result = [this.generateMockData(schema.items)];
|
|
1337
|
+
break;
|
|
1338
|
+
case "object":
|
|
1339
|
+
result = {};
|
|
1340
|
+
if (schema.properties) {
|
|
1341
|
+
for (const key in schema.properties) {
|
|
1342
|
+
result[key] = this.generateMockData(schema.properties[key]);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
break;
|
|
1346
|
+
default:
|
|
1347
|
+
result = schema.example || null;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
this.visitedSchemas.delete(schema);
|
|
1351
|
+
return result;
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
JsonDataGenerator.visitedSchemas = new Set();
|
|
1355
|
+
|
|
1307
1356
|
// Copyright (c) Microsoft Corporation.
|
|
1308
1357
|
class AdaptiveCardGenerator {
|
|
1309
|
-
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
|
|
1358
|
+
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false, maxElementCount = Number.MAX_SAFE_INTEGER) {
|
|
1310
1359
|
try {
|
|
1311
1360
|
const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
|
|
1312
1361
|
let cardBody = [];
|
|
1362
|
+
let jsonData = {};
|
|
1363
|
+
const warnings = [];
|
|
1364
|
+
const operationId = operationItem.operationId;
|
|
1313
1365
|
let schema = json.schema;
|
|
1314
1366
|
let jsonPath = "$";
|
|
1315
1367
|
if (schema && Object.keys(schema).length > 0) {
|
|
1368
|
+
try {
|
|
1369
|
+
jsonData = JsonDataGenerator.generate(schema);
|
|
1370
|
+
}
|
|
1371
|
+
catch (err) {
|
|
1372
|
+
warnings.push({
|
|
1373
|
+
type: WarningType.GenerateJsonDataFailed,
|
|
1374
|
+
content: Utils.format(ConstantString.GenerateJsonDataFailed, operationId, err.toString()),
|
|
1375
|
+
data: operationId,
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1316
1378
|
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
1317
1379
|
if (jsonPath !== "$") {
|
|
1318
1380
|
schema = schema.properties[jsonPath];
|
|
1319
1381
|
}
|
|
1320
|
-
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
1382
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "", "", maxElementCount);
|
|
1321
1383
|
}
|
|
1322
1384
|
// if no schema, try to use example value
|
|
1323
1385
|
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
@@ -1345,16 +1407,20 @@ class AdaptiveCardGenerator {
|
|
|
1345
1407
|
version: ConstantString.AdaptiveCardVersion,
|
|
1346
1408
|
body: cardBody,
|
|
1347
1409
|
};
|
|
1348
|
-
return [fullCard, jsonPath];
|
|
1410
|
+
return [fullCard, jsonPath, jsonData, warnings];
|
|
1349
1411
|
}
|
|
1350
1412
|
catch (err) {
|
|
1351
1413
|
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
1352
1414
|
}
|
|
1353
1415
|
}
|
|
1354
|
-
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
1416
|
+
static generateCardFromResponse(schema, name, parentArrayName = "", maxElementCount = Number.MAX_SAFE_INTEGER, counter = { count: 0 }) {
|
|
1417
|
+
if (counter.count >= maxElementCount) {
|
|
1418
|
+
return [];
|
|
1419
|
+
}
|
|
1355
1420
|
if (schema.type === "array") {
|
|
1356
1421
|
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
1357
1422
|
if (Object.keys(schema.items).length === 0) {
|
|
1423
|
+
counter.count++;
|
|
1358
1424
|
return [
|
|
1359
1425
|
{
|
|
1360
1426
|
type: ConstantString.TextBlockType,
|
|
@@ -1363,7 +1429,7 @@ class AdaptiveCardGenerator {
|
|
|
1363
1429
|
},
|
|
1364
1430
|
];
|
|
1365
1431
|
}
|
|
1366
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
1432
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name, maxElementCount, counter);
|
|
1367
1433
|
const template = {
|
|
1368
1434
|
type: ConstantString.ContainerType,
|
|
1369
1435
|
$data: name ? `\${${name}}` : "${$root}",
|
|
@@ -1373,11 +1439,11 @@ class AdaptiveCardGenerator {
|
|
|
1373
1439
|
return [template];
|
|
1374
1440
|
}
|
|
1375
1441
|
// some schema may not contain type but contain properties
|
|
1376
|
-
if (
|
|
1442
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1377
1443
|
const { properties } = schema;
|
|
1378
1444
|
const result = [];
|
|
1379
1445
|
for (const property in properties) {
|
|
1380
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
1446
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName, maxElementCount, counter);
|
|
1381
1447
|
result.push(...obj);
|
|
1382
1448
|
}
|
|
1383
1449
|
if (schema.additionalProperties) {
|
|
@@ -1390,6 +1456,7 @@ class AdaptiveCardGenerator {
|
|
|
1390
1456
|
schema.type === "integer" ||
|
|
1391
1457
|
schema.type === "boolean" ||
|
|
1392
1458
|
schema.type === "number") {
|
|
1459
|
+
counter.count++;
|
|
1393
1460
|
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1394
1461
|
// string in root: "ddd"
|
|
1395
1462
|
let text = "result: ${$root}";
|
|
@@ -1414,24 +1481,17 @@ class AdaptiveCardGenerator {
|
|
|
1414
1481
|
];
|
|
1415
1482
|
}
|
|
1416
1483
|
else {
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
{
|
|
1429
|
-
type: "Image",
|
|
1430
|
-
url: "${$data}",
|
|
1431
|
-
$when: "${$data != null && $data != ''}",
|
|
1432
|
-
},
|
|
1433
|
-
];
|
|
1434
|
-
}
|
|
1484
|
+
const url = name ? `\${${name}}` : "${$data}";
|
|
1485
|
+
const condition = name
|
|
1486
|
+
? `\${${name} != null && ${name} != ''}`
|
|
1487
|
+
: "${$data != null && $data != ''}";
|
|
1488
|
+
return [
|
|
1489
|
+
{
|
|
1490
|
+
type: "Image",
|
|
1491
|
+
url,
|
|
1492
|
+
$when: condition,
|
|
1493
|
+
},
|
|
1494
|
+
];
|
|
1435
1495
|
}
|
|
1436
1496
|
}
|
|
1437
1497
|
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
@@ -1441,7 +1501,7 @@ class AdaptiveCardGenerator {
|
|
|
1441
1501
|
}
|
|
1442
1502
|
// Find the first array property in the response schema object with the well-known name
|
|
1443
1503
|
static getResponseJsonPathFromSchema(schema) {
|
|
1444
|
-
if (
|
|
1504
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1445
1505
|
const { properties } = schema;
|
|
1446
1506
|
for (const property in properties) {
|
|
1447
1507
|
const schema = properties[property];
|