@microsoft/m365-spec-parser 0.2.3 → 0.2.4-alpha.e84e1682b.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 -247
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +355 -282
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +302 -247
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +355 -282
- 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.
|
|
@@ -879,7 +720,6 @@ class CopilotValidator extends Validator {
|
|
|
879
720
|
this.projectType = ProjectType.Copilot;
|
|
880
721
|
this.options = options;
|
|
881
722
|
this.spec = spec;
|
|
882
|
-
this.checkCircularReference();
|
|
883
723
|
}
|
|
884
724
|
validateSpec() {
|
|
885
725
|
const result = { errors: [], warnings: [] };
|
|
@@ -905,10 +745,6 @@ class CopilotValidator extends Validator {
|
|
|
905
745
|
if (!methodAndPathResult.isValid) {
|
|
906
746
|
return methodAndPathResult;
|
|
907
747
|
}
|
|
908
|
-
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
909
|
-
if (!circularReferenceResult.isValid) {
|
|
910
|
-
return circularReferenceResult;
|
|
911
|
-
}
|
|
912
748
|
const operationObject = this.spec.paths[path][method];
|
|
913
749
|
// validate auth
|
|
914
750
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -920,24 +756,6 @@ class CopilotValidator extends Validator {
|
|
|
920
756
|
// validate server
|
|
921
757
|
const validateServerResult = this.validateServer(method, path);
|
|
922
758
|
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
759
|
if (result.reason.length > 0) {
|
|
942
760
|
result.isValid = false;
|
|
943
761
|
}
|
|
@@ -1029,6 +847,108 @@ class SMEValidator extends Validator {
|
|
|
1029
847
|
}
|
|
1030
848
|
return result;
|
|
1031
849
|
}
|
|
850
|
+
validateResponse(method, path) {
|
|
851
|
+
const result = { isValid: true, reason: [] };
|
|
852
|
+
const operationObject = this.spec.paths[path][method];
|
|
853
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
854
|
+
// only support response body only contains “application/json” content type
|
|
855
|
+
if (multipleMediaType) {
|
|
856
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
857
|
+
}
|
|
858
|
+
else if (Object.keys(json).length === 0) {
|
|
859
|
+
// response body should not be empty
|
|
860
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
861
|
+
}
|
|
862
|
+
return result;
|
|
863
|
+
}
|
|
864
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
865
|
+
var _a;
|
|
866
|
+
const paramResult = {
|
|
867
|
+
requiredNum: 0,
|
|
868
|
+
optionalNum: 0,
|
|
869
|
+
isValid: true,
|
|
870
|
+
reason: [],
|
|
871
|
+
};
|
|
872
|
+
if (Object.keys(schema).length === 0) {
|
|
873
|
+
return paramResult;
|
|
874
|
+
}
|
|
875
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
876
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
877
|
+
if (schema.type === "string" ||
|
|
878
|
+
schema.type === "integer" ||
|
|
879
|
+
schema.type === "boolean" ||
|
|
880
|
+
schema.type === "number") {
|
|
881
|
+
if (isRequiredWithoutDefault) {
|
|
882
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
889
|
+
const { properties } = schema;
|
|
890
|
+
for (const property in properties) {
|
|
891
|
+
let isRequired = false;
|
|
892
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
893
|
+
isRequired = true;
|
|
894
|
+
}
|
|
895
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
896
|
+
paramResult.requiredNum += result.requiredNum;
|
|
897
|
+
paramResult.optionalNum += result.optionalNum;
|
|
898
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
899
|
+
paramResult.reason.push(...result.reason);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
904
|
+
paramResult.isValid = false;
|
|
905
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return paramResult;
|
|
909
|
+
}
|
|
910
|
+
checkParamSchema(paramObject) {
|
|
911
|
+
const paramResult = {
|
|
912
|
+
requiredNum: 0,
|
|
913
|
+
optionalNum: 0,
|
|
914
|
+
isValid: true,
|
|
915
|
+
reason: [],
|
|
916
|
+
};
|
|
917
|
+
if (!paramObject) {
|
|
918
|
+
return paramResult;
|
|
919
|
+
}
|
|
920
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
921
|
+
const param = paramObject[i];
|
|
922
|
+
const schema = param.schema;
|
|
923
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
924
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
925
|
+
if (isRequiredWithoutDefault) {
|
|
926
|
+
paramResult.isValid = false;
|
|
927
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
928
|
+
}
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
if (schema.type !== "boolean" &&
|
|
932
|
+
schema.type !== "string" &&
|
|
933
|
+
schema.type !== "number" &&
|
|
934
|
+
schema.type !== "integer") {
|
|
935
|
+
if (isRequiredWithoutDefault) {
|
|
936
|
+
paramResult.isValid = false;
|
|
937
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
938
|
+
}
|
|
939
|
+
continue;
|
|
940
|
+
}
|
|
941
|
+
if (param.in === "query" || param.in === "path") {
|
|
942
|
+
if (isRequiredWithoutDefault) {
|
|
943
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
944
|
+
}
|
|
945
|
+
else {
|
|
946
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return paramResult;
|
|
951
|
+
}
|
|
1032
952
|
validateParamCount(postBodyResult, paramResult) {
|
|
1033
953
|
const result = { isValid: true, reason: [] };
|
|
1034
954
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
@@ -1304,20 +1224,157 @@ class SpecParser {
|
|
|
1304
1224
|
}
|
|
1305
1225
|
}
|
|
1306
1226
|
|
|
1227
|
+
// Copyright (c) Microsoft Corporation.
|
|
1228
|
+
class JsonDataGenerator {
|
|
1229
|
+
static generate(schema) {
|
|
1230
|
+
return this.generateMockData(schema);
|
|
1231
|
+
}
|
|
1232
|
+
static generateMockData(schema) {
|
|
1233
|
+
if (this.visitedSchemas.has(schema)) {
|
|
1234
|
+
return null; // Prevent circular reference
|
|
1235
|
+
}
|
|
1236
|
+
this.visitedSchemas.add(schema);
|
|
1237
|
+
let result;
|
|
1238
|
+
if (schema.anyOf) {
|
|
1239
|
+
// Select the first schema in anyOf
|
|
1240
|
+
const selectedSchema = schema.anyOf[0];
|
|
1241
|
+
result = this.generateMockData(selectedSchema);
|
|
1242
|
+
}
|
|
1243
|
+
else if (schema.oneOf) {
|
|
1244
|
+
// Select the first schema in oneOf
|
|
1245
|
+
const selectedSchema = schema.oneOf[0];
|
|
1246
|
+
result = this.generateMockData(selectedSchema);
|
|
1247
|
+
}
|
|
1248
|
+
else if (schema.allOf) {
|
|
1249
|
+
// merge all schemas in allOf
|
|
1250
|
+
result = {};
|
|
1251
|
+
for (const subschema of schema.allOf) {
|
|
1252
|
+
const data = this.generateMockData(subschema);
|
|
1253
|
+
result = Object.assign(Object.assign({}, result), data);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
else {
|
|
1257
|
+
switch (schema.type) {
|
|
1258
|
+
case "string":
|
|
1259
|
+
if (schema.example !== undefined) {
|
|
1260
|
+
result = schema.example;
|
|
1261
|
+
}
|
|
1262
|
+
else if (schema.format) {
|
|
1263
|
+
switch (schema.format) {
|
|
1264
|
+
case "date-time":
|
|
1265
|
+
result = "2024-11-01T05:25:43.593Z";
|
|
1266
|
+
break;
|
|
1267
|
+
case "email":
|
|
1268
|
+
result = "example@example.com";
|
|
1269
|
+
break;
|
|
1270
|
+
case "uuid":
|
|
1271
|
+
result = "123e4567-e89b-12d3-a456-426614174000";
|
|
1272
|
+
break;
|
|
1273
|
+
case "ipv4":
|
|
1274
|
+
result = "192.168.0.1";
|
|
1275
|
+
break;
|
|
1276
|
+
case "ipv6":
|
|
1277
|
+
result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
|
|
1278
|
+
break;
|
|
1279
|
+
default:
|
|
1280
|
+
result = "example string";
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
else {
|
|
1284
|
+
result = "example string";
|
|
1285
|
+
}
|
|
1286
|
+
break;
|
|
1287
|
+
case "number":
|
|
1288
|
+
if (schema.example !== undefined) {
|
|
1289
|
+
result = schema.example;
|
|
1290
|
+
}
|
|
1291
|
+
else if (schema.format) {
|
|
1292
|
+
switch (schema.format) {
|
|
1293
|
+
case "float":
|
|
1294
|
+
result = 3.14;
|
|
1295
|
+
break;
|
|
1296
|
+
case "double":
|
|
1297
|
+
result = 3.14159;
|
|
1298
|
+
break;
|
|
1299
|
+
default:
|
|
1300
|
+
result = 123;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
else {
|
|
1304
|
+
result = 123;
|
|
1305
|
+
}
|
|
1306
|
+
break;
|
|
1307
|
+
case "integer":
|
|
1308
|
+
if (schema.example !== undefined) {
|
|
1309
|
+
result = schema.example;
|
|
1310
|
+
}
|
|
1311
|
+
else if (schema.format) {
|
|
1312
|
+
switch (schema.format) {
|
|
1313
|
+
case "int32":
|
|
1314
|
+
result = 123456;
|
|
1315
|
+
break;
|
|
1316
|
+
case "int64":
|
|
1317
|
+
result = 123456789;
|
|
1318
|
+
break;
|
|
1319
|
+
default:
|
|
1320
|
+
result = 123;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
else {
|
|
1324
|
+
result = 123;
|
|
1325
|
+
}
|
|
1326
|
+
break;
|
|
1327
|
+
case "boolean":
|
|
1328
|
+
result = schema.example !== undefined ? schema.example : true;
|
|
1329
|
+
break;
|
|
1330
|
+
case "array":
|
|
1331
|
+
result = [this.generateMockData(schema.items)];
|
|
1332
|
+
break;
|
|
1333
|
+
case "object":
|
|
1334
|
+
result = {};
|
|
1335
|
+
if (schema.properties) {
|
|
1336
|
+
for (const key in schema.properties) {
|
|
1337
|
+
result[key] = this.generateMockData(schema.properties[key]);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
break;
|
|
1341
|
+
default:
|
|
1342
|
+
result = schema.example || null;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
this.visitedSchemas.delete(schema);
|
|
1346
|
+
return result;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
JsonDataGenerator.visitedSchemas = new Set();
|
|
1350
|
+
|
|
1307
1351
|
// Copyright (c) Microsoft Corporation.
|
|
1308
1352
|
class AdaptiveCardGenerator {
|
|
1309
|
-
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
|
|
1353
|
+
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false, maxElementCount = Number.MAX_SAFE_INTEGER) {
|
|
1310
1354
|
try {
|
|
1311
1355
|
const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
|
|
1312
1356
|
let cardBody = [];
|
|
1357
|
+
let jsonData = {};
|
|
1358
|
+
const warnings = [];
|
|
1359
|
+
const operationId = operationItem.operationId;
|
|
1313
1360
|
let schema = json.schema;
|
|
1314
1361
|
let jsonPath = "$";
|
|
1315
1362
|
if (schema && Object.keys(schema).length > 0) {
|
|
1363
|
+
try {
|
|
1364
|
+
jsonData = JsonDataGenerator.generate(schema);
|
|
1365
|
+
}
|
|
1366
|
+
catch (err) {
|
|
1367
|
+
warnings.push({
|
|
1368
|
+
type: WarningType.GenerateJsonDataFailed,
|
|
1369
|
+
content: Utils.format(ConstantString.GenerateJsonDataFailed, operationId, err.toString()),
|
|
1370
|
+
data: operationId,
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1316
1373
|
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
1317
1374
|
if (jsonPath !== "$") {
|
|
1318
1375
|
schema = schema.properties[jsonPath];
|
|
1319
1376
|
}
|
|
1320
|
-
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
1377
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "", "", maxElementCount);
|
|
1321
1378
|
}
|
|
1322
1379
|
// if no schema, try to use example value
|
|
1323
1380
|
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
@@ -1345,16 +1402,20 @@ class AdaptiveCardGenerator {
|
|
|
1345
1402
|
version: ConstantString.AdaptiveCardVersion,
|
|
1346
1403
|
body: cardBody,
|
|
1347
1404
|
};
|
|
1348
|
-
return [fullCard, jsonPath];
|
|
1405
|
+
return [fullCard, jsonPath, jsonData, warnings];
|
|
1349
1406
|
}
|
|
1350
1407
|
catch (err) {
|
|
1351
1408
|
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
1352
1409
|
}
|
|
1353
1410
|
}
|
|
1354
|
-
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
1411
|
+
static generateCardFromResponse(schema, name, parentArrayName = "", maxElementCount = Number.MAX_SAFE_INTEGER, counter = { count: 0 }) {
|
|
1412
|
+
if (counter.count >= maxElementCount) {
|
|
1413
|
+
return [];
|
|
1414
|
+
}
|
|
1355
1415
|
if (schema.type === "array") {
|
|
1356
1416
|
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
1357
1417
|
if (Object.keys(schema.items).length === 0) {
|
|
1418
|
+
counter.count++;
|
|
1358
1419
|
return [
|
|
1359
1420
|
{
|
|
1360
1421
|
type: ConstantString.TextBlockType,
|
|
@@ -1363,7 +1424,7 @@ class AdaptiveCardGenerator {
|
|
|
1363
1424
|
},
|
|
1364
1425
|
];
|
|
1365
1426
|
}
|
|
1366
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
1427
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name, maxElementCount, counter);
|
|
1367
1428
|
const template = {
|
|
1368
1429
|
type: ConstantString.ContainerType,
|
|
1369
1430
|
$data: name ? `\${${name}}` : "${$root}",
|
|
@@ -1373,11 +1434,11 @@ class AdaptiveCardGenerator {
|
|
|
1373
1434
|
return [template];
|
|
1374
1435
|
}
|
|
1375
1436
|
// some schema may not contain type but contain properties
|
|
1376
|
-
if (
|
|
1437
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1377
1438
|
const { properties } = schema;
|
|
1378
1439
|
const result = [];
|
|
1379
1440
|
for (const property in properties) {
|
|
1380
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
1441
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName, maxElementCount, counter);
|
|
1381
1442
|
result.push(...obj);
|
|
1382
1443
|
}
|
|
1383
1444
|
if (schema.additionalProperties) {
|
|
@@ -1390,6 +1451,7 @@ class AdaptiveCardGenerator {
|
|
|
1390
1451
|
schema.type === "integer" ||
|
|
1391
1452
|
schema.type === "boolean" ||
|
|
1392
1453
|
schema.type === "number") {
|
|
1454
|
+
counter.count++;
|
|
1393
1455
|
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1394
1456
|
// string in root: "ddd"
|
|
1395
1457
|
let text = "result: ${$root}";
|
|
@@ -1414,24 +1476,17 @@ class AdaptiveCardGenerator {
|
|
|
1414
1476
|
];
|
|
1415
1477
|
}
|
|
1416
1478
|
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
|
-
}
|
|
1479
|
+
const url = name ? `\${${name}}` : "${$data}";
|
|
1480
|
+
const condition = name
|
|
1481
|
+
? `\${${name} != null && ${name} != ''}`
|
|
1482
|
+
: "${$data != null && $data != ''}";
|
|
1483
|
+
return [
|
|
1484
|
+
{
|
|
1485
|
+
type: "Image",
|
|
1486
|
+
url,
|
|
1487
|
+
$when: condition,
|
|
1488
|
+
},
|
|
1489
|
+
];
|
|
1435
1490
|
}
|
|
1436
1491
|
}
|
|
1437
1492
|
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
@@ -1441,7 +1496,7 @@ class AdaptiveCardGenerator {
|
|
|
1441
1496
|
}
|
|
1442
1497
|
// Find the first array property in the response schema object with the well-known name
|
|
1443
1498
|
static getResponseJsonPathFromSchema(schema) {
|
|
1444
|
-
if (
|
|
1499
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1445
1500
|
const { properties } = schema;
|
|
1446
1501
|
for (const property in properties) {
|
|
1447
1502
|
const schema = properties[property];
|