@microsoft/m365-spec-parser 0.2.4-rc.0 → 0.2.4
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 +193 -176
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +276 -299
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +193 -176
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +277 -302
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +4 -3
- package/dist/src/interfaces.d.ts +3 -10
- package/dist/src/manifestUpdater.d.ts +3 -3
- package/dist/src/specParser.d.ts +0 -2
- package/dist/src/utils.d.ts +3 -6
- package/package.json +4 -4
package/dist/index.esm5.js
CHANGED
|
@@ -62,8 +62,11 @@ 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";
|
|
65
66
|
ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
|
|
66
67
|
ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
|
|
68
|
+
ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
|
|
69
|
+
ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
|
|
67
70
|
ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
|
|
68
71
|
ErrorType["NoParameter"] = "no-parameter";
|
|
69
72
|
ErrorType["NoAPIInfo"] = "no-api-info";
|
|
@@ -83,7 +86,6 @@ var WarningType;
|
|
|
83
86
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
84
87
|
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
85
88
|
WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
|
|
86
|
-
WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
|
|
87
89
|
WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
88
90
|
WarningType["Unknown"] = "unknown";
|
|
89
91
|
})(WarningType || (WarningType = {}));
|
|
@@ -131,7 +133,6 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
|
|
|
131
133
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
132
134
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
133
135
|
ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
|
|
134
|
-
ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
|
|
135
136
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
136
137
|
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.";
|
|
137
138
|
ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
|
|
@@ -141,12 +142,17 @@ ConstantString.WrappedCardResponseLayout = "list";
|
|
|
141
142
|
ConstantString.GetMethod = "get";
|
|
142
143
|
ConstantString.PostMethod = "post";
|
|
143
144
|
ConstantString.AdaptiveCardVersion = "1.5";
|
|
144
|
-
ConstantString.AdaptiveCardSchema = "
|
|
145
|
+
ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
|
|
145
146
|
ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
146
147
|
ConstantString.TextBlockType = "TextBlock";
|
|
147
148
|
ConstantString.ImageType = "Image";
|
|
148
149
|
ConstantString.ContainerType = "Container";
|
|
149
|
-
ConstantString.RegistrationIdPostfix =
|
|
150
|
+
ConstantString.RegistrationIdPostfix = {
|
|
151
|
+
apiKey: "REGISTRATION_ID",
|
|
152
|
+
oauth2: "CONFIGURATION_ID",
|
|
153
|
+
http: "REGISTRATION_ID",
|
|
154
|
+
openIdConnect: "REGISTRATION_ID",
|
|
155
|
+
};
|
|
150
156
|
ConstantString.ResponseCodeFor20X = [
|
|
151
157
|
"200",
|
|
152
158
|
"201",
|
|
@@ -158,7 +164,6 @@ ConstantString.ResponseCodeFor20X = [
|
|
|
158
164
|
"207",
|
|
159
165
|
"208",
|
|
160
166
|
"226",
|
|
161
|
-
"2XX",
|
|
162
167
|
"default",
|
|
163
168
|
];
|
|
164
169
|
ConstantString.AllOperationMethods = [
|
|
@@ -216,6 +221,17 @@ ConstantString.PluginManifestSchema = "https://developer.microsoft.com/json-sche
|
|
|
216
221
|
|
|
217
222
|
// Copyright (c) Microsoft Corporation.
|
|
218
223
|
class Utils {
|
|
224
|
+
static hasNestedObjectInSchema(schema) {
|
|
225
|
+
if (this.isObjectSchema(schema)) {
|
|
226
|
+
for (const property in schema.properties) {
|
|
227
|
+
const nestedSchema = schema.properties[property];
|
|
228
|
+
if (this.isObjectSchema(nestedSchema)) {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
219
235
|
static isObjectSchema(schema) {
|
|
220
236
|
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
221
237
|
}
|
|
@@ -228,32 +244,11 @@ class Utils {
|
|
|
228
244
|
static isAPIKeyAuth(authScheme) {
|
|
229
245
|
return authScheme.type === "apiKey";
|
|
230
246
|
}
|
|
231
|
-
static isAPIKeyAuthButNotInCookie(authScheme) {
|
|
232
|
-
return authScheme.type === "apiKey" && authScheme.in !== "cookie";
|
|
233
|
-
}
|
|
234
247
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
235
248
|
return !!(authScheme.type === "oauth2" &&
|
|
236
249
|
authScheme.flows &&
|
|
237
250
|
authScheme.flows.authorizationCode);
|
|
238
251
|
}
|
|
239
|
-
static isNotSupportedAuth(authSchemeArray) {
|
|
240
|
-
if (authSchemeArray.length === 0) {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
244
|
-
return true;
|
|
245
|
-
}
|
|
246
|
-
for (const auths of authSchemeArray) {
|
|
247
|
-
if (auths.length === 1) {
|
|
248
|
-
if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
|
|
249
|
-
Utils.isBearerTokenAuth(auths[0].authScheme) ||
|
|
250
|
-
Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return true;
|
|
256
|
-
}
|
|
257
252
|
static getAuthArray(securities, spec) {
|
|
258
253
|
var _a;
|
|
259
254
|
const result = [];
|
|
@@ -278,20 +273,6 @@ class Utils {
|
|
|
278
273
|
result.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
279
274
|
return result;
|
|
280
275
|
}
|
|
281
|
-
static getAuthMap(spec) {
|
|
282
|
-
const authMap = {};
|
|
283
|
-
for (const url in spec.paths) {
|
|
284
|
-
for (const method in spec.paths[url]) {
|
|
285
|
-
const operation = spec.paths[url][method];
|
|
286
|
-
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
287
|
-
if (authArray && authArray.length > 0) {
|
|
288
|
-
const currentAuth = authArray[0][0];
|
|
289
|
-
authMap[operation.operationId] = currentAuth;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return authMap;
|
|
294
|
-
}
|
|
295
276
|
static getAuthInfo(spec) {
|
|
296
277
|
let authInfo = undefined;
|
|
297
278
|
for (const url in spec.paths) {
|
|
@@ -320,32 +301,26 @@ class Utils {
|
|
|
320
301
|
let multipleMediaType = false;
|
|
321
302
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
322
303
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
323
|
-
if (
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
static getJsonContentType(responseObject) {
|
|
340
|
-
if (responseObject.content) {
|
|
341
|
-
for (const contentType of Object.keys(responseObject.content)) {
|
|
342
|
-
// json media type can also be "application/json; charset=utf-8"
|
|
343
|
-
if (contentType.indexOf("application/json") >= 0) {
|
|
344
|
-
return responseObject.content[contentType];
|
|
304
|
+
if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
|
|
305
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
306
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
307
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
308
|
+
multipleMediaType = false;
|
|
309
|
+
json = responseObject.content[contentType];
|
|
310
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
311
|
+
multipleMediaType = true;
|
|
312
|
+
if (!allowMultipleMediaType) {
|
|
313
|
+
json = {};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
return { json, multipleMediaType };
|
|
318
|
+
}
|
|
319
|
+
}
|
|
345
320
|
}
|
|
346
321
|
}
|
|
347
322
|
}
|
|
348
|
-
return {};
|
|
323
|
+
return { json, multipleMediaType };
|
|
349
324
|
}
|
|
350
325
|
static convertPathToCamelCase(path) {
|
|
351
326
|
const pathSegments = path.split(/[./{]/);
|
|
@@ -382,7 +357,7 @@ class Utils {
|
|
|
382
357
|
}
|
|
383
358
|
return newStr;
|
|
384
359
|
}
|
|
385
|
-
static checkServerUrl(servers
|
|
360
|
+
static checkServerUrl(servers) {
|
|
386
361
|
const errors = [];
|
|
387
362
|
let serverUrl;
|
|
388
363
|
try {
|
|
@@ -405,7 +380,8 @@ class Utils {
|
|
|
405
380
|
data: servers,
|
|
406
381
|
});
|
|
407
382
|
}
|
|
408
|
-
else if (protocol !== "https:"
|
|
383
|
+
else if (protocol !== "https:") {
|
|
384
|
+
// Http server url is not supported
|
|
409
385
|
const protocolString = protocol.slice(0, -1);
|
|
410
386
|
errors.push({
|
|
411
387
|
type: ErrorType.UrlProtocolNotSupported,
|
|
@@ -421,11 +397,10 @@ class Utils {
|
|
|
421
397
|
let hasTopLevelServers = false;
|
|
422
398
|
let hasPathLevelServers = false;
|
|
423
399
|
let hasOperationLevelServers = false;
|
|
424
|
-
const allowHttp = options.projectType === ProjectType.Copilot;
|
|
425
400
|
if (spec.servers && spec.servers.length >= 1) {
|
|
426
401
|
hasTopLevelServers = true;
|
|
427
402
|
// for multiple server, we only use the first url
|
|
428
|
-
const serverErrors = Utils.checkServerUrl(spec.servers
|
|
403
|
+
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
429
404
|
errors.push(...serverErrors);
|
|
430
405
|
}
|
|
431
406
|
const paths = spec.paths;
|
|
@@ -433,7 +408,7 @@ class Utils {
|
|
|
433
408
|
const methods = paths[path];
|
|
434
409
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
435
410
|
hasPathLevelServers = true;
|
|
436
|
-
const serverErrors = Utils.checkServerUrl(methods.servers
|
|
411
|
+
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
437
412
|
errors.push(...serverErrors);
|
|
438
413
|
}
|
|
439
414
|
for (const method in methods) {
|
|
@@ -441,7 +416,7 @@ class Utils {
|
|
|
441
416
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
442
417
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
443
418
|
hasOperationLevelServers = true;
|
|
444
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers
|
|
419
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
445
420
|
errors.push(...serverErrors);
|
|
446
421
|
}
|
|
447
422
|
}
|
|
@@ -730,6 +705,22 @@ class Validator {
|
|
|
730
705
|
}
|
|
731
706
|
return result;
|
|
732
707
|
}
|
|
708
|
+
validateResponse(method, path) {
|
|
709
|
+
const result = { isValid: true, reason: [] };
|
|
710
|
+
const operationObject = this.spec.paths[path][method];
|
|
711
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
712
|
+
if (this.options.projectType === ProjectType.SME) {
|
|
713
|
+
// only support response body only contains “application/json” content type
|
|
714
|
+
if (multipleMediaType) {
|
|
715
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
716
|
+
}
|
|
717
|
+
else if (Object.keys(json).length === 0) {
|
|
718
|
+
// response body should not be empty
|
|
719
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return result;
|
|
723
|
+
}
|
|
733
724
|
validateServer(method, path) {
|
|
734
725
|
const result = { isValid: true, reason: [] };
|
|
735
726
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -738,8 +729,8 @@ class Validator {
|
|
|
738
729
|
result.reason.push(ErrorType.NoServerInformation);
|
|
739
730
|
}
|
|
740
731
|
else {
|
|
741
|
-
|
|
742
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]
|
|
732
|
+
// server url should be absolute url with https protocol
|
|
733
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
743
734
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
744
735
|
}
|
|
745
736
|
return result;
|
|
@@ -762,9 +753,6 @@ class Validator {
|
|
|
762
753
|
reason: [ErrorType.MultipleAuthNotSupported],
|
|
763
754
|
};
|
|
764
755
|
}
|
|
765
|
-
if (this.projectType === ProjectType.Copilot) {
|
|
766
|
-
return { isValid: true, reason: [] };
|
|
767
|
-
}
|
|
768
756
|
for (const auths of authSchemeArray) {
|
|
769
757
|
if (auths.length === 1) {
|
|
770
758
|
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
@@ -777,6 +765,114 @@ class Validator {
|
|
|
777
765
|
}
|
|
778
766
|
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
779
767
|
}
|
|
768
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
769
|
+
var _a;
|
|
770
|
+
const paramResult = {
|
|
771
|
+
requiredNum: 0,
|
|
772
|
+
optionalNum: 0,
|
|
773
|
+
isValid: true,
|
|
774
|
+
reason: [],
|
|
775
|
+
};
|
|
776
|
+
if (Object.keys(schema).length === 0) {
|
|
777
|
+
return paramResult;
|
|
778
|
+
}
|
|
779
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
780
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
781
|
+
if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
|
|
782
|
+
paramResult.isValid = false;
|
|
783
|
+
paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
|
|
784
|
+
return paramResult;
|
|
785
|
+
}
|
|
786
|
+
if (schema.type === "string" ||
|
|
787
|
+
schema.type === "integer" ||
|
|
788
|
+
schema.type === "boolean" ||
|
|
789
|
+
schema.type === "number") {
|
|
790
|
+
if (isRequiredWithoutDefault) {
|
|
791
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
798
|
+
const { properties } = schema;
|
|
799
|
+
for (const property in properties) {
|
|
800
|
+
let isRequired = false;
|
|
801
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
802
|
+
isRequired = true;
|
|
803
|
+
}
|
|
804
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
805
|
+
paramResult.requiredNum += result.requiredNum;
|
|
806
|
+
paramResult.optionalNum += result.optionalNum;
|
|
807
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
808
|
+
paramResult.reason.push(...result.reason);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
else {
|
|
812
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
813
|
+
paramResult.isValid = false;
|
|
814
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return paramResult;
|
|
818
|
+
}
|
|
819
|
+
checkParamSchema(paramObject) {
|
|
820
|
+
const paramResult = {
|
|
821
|
+
requiredNum: 0,
|
|
822
|
+
optionalNum: 0,
|
|
823
|
+
isValid: true,
|
|
824
|
+
reason: [],
|
|
825
|
+
};
|
|
826
|
+
if (!paramObject) {
|
|
827
|
+
return paramResult;
|
|
828
|
+
}
|
|
829
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
830
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
831
|
+
const param = paramObject[i];
|
|
832
|
+
const schema = param.schema;
|
|
833
|
+
if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
|
|
834
|
+
paramResult.isValid = false;
|
|
835
|
+
paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
839
|
+
if (isCopilot) {
|
|
840
|
+
if (isRequiredWithoutDefault) {
|
|
841
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
845
|
+
}
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
849
|
+
if (isRequiredWithoutDefault) {
|
|
850
|
+
paramResult.isValid = false;
|
|
851
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
852
|
+
}
|
|
853
|
+
continue;
|
|
854
|
+
}
|
|
855
|
+
if (schema.type !== "boolean" &&
|
|
856
|
+
schema.type !== "string" &&
|
|
857
|
+
schema.type !== "number" &&
|
|
858
|
+
schema.type !== "integer") {
|
|
859
|
+
if (isRequiredWithoutDefault) {
|
|
860
|
+
paramResult.isValid = false;
|
|
861
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
862
|
+
}
|
|
863
|
+
continue;
|
|
864
|
+
}
|
|
865
|
+
if (param.in === "query" || param.in === "path") {
|
|
866
|
+
if (isRequiredWithoutDefault) {
|
|
867
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return paramResult;
|
|
875
|
+
}
|
|
780
876
|
}
|
|
781
877
|
|
|
782
878
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -786,6 +882,7 @@ class CopilotValidator extends Validator {
|
|
|
786
882
|
this.projectType = ProjectType.Copilot;
|
|
787
883
|
this.options = options;
|
|
788
884
|
this.spec = spec;
|
|
885
|
+
this.checkCircularReference();
|
|
789
886
|
}
|
|
790
887
|
validateSpec() {
|
|
791
888
|
const result = { errors: [], warnings: [] };
|
|
@@ -811,6 +908,10 @@ class CopilotValidator extends Validator {
|
|
|
811
908
|
if (!methodAndPathResult.isValid) {
|
|
812
909
|
return methodAndPathResult;
|
|
813
910
|
}
|
|
911
|
+
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
912
|
+
if (!circularReferenceResult.isValid) {
|
|
913
|
+
return circularReferenceResult;
|
|
914
|
+
}
|
|
814
915
|
const operationObject = this.spec.paths[path][method];
|
|
815
916
|
// validate auth
|
|
816
917
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -822,6 +923,24 @@ class CopilotValidator extends Validator {
|
|
|
822
923
|
// validate server
|
|
823
924
|
const validateServerResult = this.validateServer(method, path);
|
|
824
925
|
result.reason.push(...validateServerResult.reason);
|
|
926
|
+
// validate response
|
|
927
|
+
const validateResponseResult = this.validateResponse(method, path);
|
|
928
|
+
result.reason.push(...validateResponseResult.reason);
|
|
929
|
+
// validate requestBody
|
|
930
|
+
const requestBody = operationObject.requestBody;
|
|
931
|
+
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
932
|
+
if (requestJsonBody) {
|
|
933
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
934
|
+
if (!Utils.isObjectSchema(requestBodySchema)) {
|
|
935
|
+
result.reason.push(ErrorType.PostBodySchemaIsNotJson);
|
|
936
|
+
}
|
|
937
|
+
const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
938
|
+
result.reason.push(...requestBodyParamResult.reason);
|
|
939
|
+
}
|
|
940
|
+
// validate parameters
|
|
941
|
+
const paramObject = operationObject.parameters;
|
|
942
|
+
const paramResult = this.checkParamSchema(paramObject);
|
|
943
|
+
result.reason.push(...paramResult.reason);
|
|
825
944
|
if (result.reason.length > 0) {
|
|
826
945
|
result.isValid = false;
|
|
827
946
|
}
|
|
@@ -913,108 +1032,6 @@ class SMEValidator extends Validator {
|
|
|
913
1032
|
}
|
|
914
1033
|
return result;
|
|
915
1034
|
}
|
|
916
|
-
validateResponse(method, path) {
|
|
917
|
-
const result = { isValid: true, reason: [] };
|
|
918
|
-
const operationObject = this.spec.paths[path][method];
|
|
919
|
-
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
920
|
-
// only support response body only contains “application/json” content type
|
|
921
|
-
if (multipleMediaType) {
|
|
922
|
-
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
923
|
-
}
|
|
924
|
-
else if (Object.keys(json).length === 0) {
|
|
925
|
-
// response body should not be empty
|
|
926
|
-
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
927
|
-
}
|
|
928
|
-
return result;
|
|
929
|
-
}
|
|
930
|
-
checkPostBodySchema(schema, isRequired = false) {
|
|
931
|
-
var _a;
|
|
932
|
-
const paramResult = {
|
|
933
|
-
requiredNum: 0,
|
|
934
|
-
optionalNum: 0,
|
|
935
|
-
isValid: true,
|
|
936
|
-
reason: [],
|
|
937
|
-
};
|
|
938
|
-
if (Object.keys(schema).length === 0) {
|
|
939
|
-
return paramResult;
|
|
940
|
-
}
|
|
941
|
-
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
942
|
-
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
943
|
-
if (schema.type === "string" ||
|
|
944
|
-
schema.type === "integer" ||
|
|
945
|
-
schema.type === "boolean" ||
|
|
946
|
-
schema.type === "number") {
|
|
947
|
-
if (isRequiredWithoutDefault) {
|
|
948
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
949
|
-
}
|
|
950
|
-
else {
|
|
951
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
else if (Utils.isObjectSchema(schema)) {
|
|
955
|
-
const { properties } = schema;
|
|
956
|
-
for (const property in properties) {
|
|
957
|
-
let isRequired = false;
|
|
958
|
-
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
959
|
-
isRequired = true;
|
|
960
|
-
}
|
|
961
|
-
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
962
|
-
paramResult.requiredNum += result.requiredNum;
|
|
963
|
-
paramResult.optionalNum += result.optionalNum;
|
|
964
|
-
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
965
|
-
paramResult.reason.push(...result.reason);
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
else {
|
|
969
|
-
if (isRequiredWithoutDefault && !isCopilot) {
|
|
970
|
-
paramResult.isValid = false;
|
|
971
|
-
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
return paramResult;
|
|
975
|
-
}
|
|
976
|
-
checkParamSchema(paramObject) {
|
|
977
|
-
const paramResult = {
|
|
978
|
-
requiredNum: 0,
|
|
979
|
-
optionalNum: 0,
|
|
980
|
-
isValid: true,
|
|
981
|
-
reason: [],
|
|
982
|
-
};
|
|
983
|
-
if (!paramObject) {
|
|
984
|
-
return paramResult;
|
|
985
|
-
}
|
|
986
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
987
|
-
const param = paramObject[i];
|
|
988
|
-
const schema = param.schema;
|
|
989
|
-
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
990
|
-
if (param.in === "header" || param.in === "cookie") {
|
|
991
|
-
if (isRequiredWithoutDefault) {
|
|
992
|
-
paramResult.isValid = false;
|
|
993
|
-
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
994
|
-
}
|
|
995
|
-
continue;
|
|
996
|
-
}
|
|
997
|
-
if (schema.type !== "boolean" &&
|
|
998
|
-
schema.type !== "string" &&
|
|
999
|
-
schema.type !== "number" &&
|
|
1000
|
-
schema.type !== "integer") {
|
|
1001
|
-
if (isRequiredWithoutDefault) {
|
|
1002
|
-
paramResult.isValid = false;
|
|
1003
|
-
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
1004
|
-
}
|
|
1005
|
-
continue;
|
|
1006
|
-
}
|
|
1007
|
-
if (param.in === "query" || param.in === "path") {
|
|
1008
|
-
if (isRequiredWithoutDefault) {
|
|
1009
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
1010
|
-
}
|
|
1011
|
-
else {
|
|
1012
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
return paramResult;
|
|
1017
|
-
}
|
|
1018
1035
|
validateParamCount(postBodyResult, paramResult) {
|
|
1019
1036
|
const result = { isValid: true, reason: [] };
|
|
1020
1037
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|