@microsoft/m365-spec-parser 0.2.5-rc.0 → 0.2.5
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 +6 -5
package/dist/index.esm2017.js
CHANGED
|
@@ -32,8 +32,11 @@ 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";
|
|
35
36
|
ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
|
|
36
37
|
ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
|
|
38
|
+
ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
|
|
39
|
+
ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
|
|
37
40
|
ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
|
|
38
41
|
ErrorType["NoParameter"] = "no-parameter";
|
|
39
42
|
ErrorType["NoAPIInfo"] = "no-api-info";
|
|
@@ -53,7 +56,6 @@ var WarningType;
|
|
|
53
56
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
54
57
|
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
55
58
|
WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
|
|
56
|
-
WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
|
|
57
59
|
WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
58
60
|
WarningType["Unknown"] = "unknown";
|
|
59
61
|
})(WarningType || (WarningType = {}));
|
|
@@ -101,7 +103,6 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
|
|
|
101
103
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
102
104
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
103
105
|
ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
|
|
104
|
-
ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
|
|
105
106
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
106
107
|
ConstantString.FuncDescriptionTooLong = "The description of the function '%s' is too long. The current length is %s characters, while the maximum allowed length is %s characters.";
|
|
107
108
|
ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
|
|
@@ -111,12 +112,17 @@ ConstantString.WrappedCardResponseLayout = "list";
|
|
|
111
112
|
ConstantString.GetMethod = "get";
|
|
112
113
|
ConstantString.PostMethod = "post";
|
|
113
114
|
ConstantString.AdaptiveCardVersion = "1.5";
|
|
114
|
-
ConstantString.AdaptiveCardSchema = "
|
|
115
|
+
ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
|
|
115
116
|
ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
116
117
|
ConstantString.TextBlockType = "TextBlock";
|
|
117
118
|
ConstantString.ImageType = "Image";
|
|
118
119
|
ConstantString.ContainerType = "Container";
|
|
119
|
-
ConstantString.RegistrationIdPostfix =
|
|
120
|
+
ConstantString.RegistrationIdPostfix = {
|
|
121
|
+
apiKey: "REGISTRATION_ID",
|
|
122
|
+
oauth2: "CONFIGURATION_ID",
|
|
123
|
+
http: "REGISTRATION_ID",
|
|
124
|
+
openIdConnect: "REGISTRATION_ID",
|
|
125
|
+
};
|
|
120
126
|
ConstantString.ResponseCodeFor20X = [
|
|
121
127
|
"200",
|
|
122
128
|
"201",
|
|
@@ -128,7 +134,6 @@ ConstantString.ResponseCodeFor20X = [
|
|
|
128
134
|
"207",
|
|
129
135
|
"208",
|
|
130
136
|
"226",
|
|
131
|
-
"2XX",
|
|
132
137
|
"default",
|
|
133
138
|
];
|
|
134
139
|
ConstantString.AllOperationMethods = [
|
|
@@ -186,6 +191,17 @@ ConstantString.PluginManifestSchema = "https://developer.microsoft.com/json-sche
|
|
|
186
191
|
|
|
187
192
|
// Copyright (c) Microsoft Corporation.
|
|
188
193
|
class Utils {
|
|
194
|
+
static hasNestedObjectInSchema(schema) {
|
|
195
|
+
if (this.isObjectSchema(schema)) {
|
|
196
|
+
for (const property in schema.properties) {
|
|
197
|
+
const nestedSchema = schema.properties[property];
|
|
198
|
+
if (this.isObjectSchema(nestedSchema)) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
189
205
|
static isObjectSchema(schema) {
|
|
190
206
|
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
191
207
|
}
|
|
@@ -198,32 +214,11 @@ class Utils {
|
|
|
198
214
|
static isAPIKeyAuth(authScheme) {
|
|
199
215
|
return authScheme.type === "apiKey";
|
|
200
216
|
}
|
|
201
|
-
static isAPIKeyAuthButNotInCookie(authScheme) {
|
|
202
|
-
return authScheme.type === "apiKey" && authScheme.in !== "cookie";
|
|
203
|
-
}
|
|
204
217
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
205
218
|
return !!(authScheme.type === "oauth2" &&
|
|
206
219
|
authScheme.flows &&
|
|
207
220
|
authScheme.flows.authorizationCode);
|
|
208
221
|
}
|
|
209
|
-
static isNotSupportedAuth(authSchemeArray) {
|
|
210
|
-
if (authSchemeArray.length === 0) {
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
|
-
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
214
|
-
return true;
|
|
215
|
-
}
|
|
216
|
-
for (const auths of authSchemeArray) {
|
|
217
|
-
if (auths.length === 1) {
|
|
218
|
-
if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
|
|
219
|
-
Utils.isBearerTokenAuth(auths[0].authScheme) ||
|
|
220
|
-
Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
return true;
|
|
226
|
-
}
|
|
227
222
|
static getAuthArray(securities, spec) {
|
|
228
223
|
var _a;
|
|
229
224
|
const result = [];
|
|
@@ -248,20 +243,6 @@ class Utils {
|
|
|
248
243
|
result.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
249
244
|
return result;
|
|
250
245
|
}
|
|
251
|
-
static getAuthMap(spec) {
|
|
252
|
-
const authMap = {};
|
|
253
|
-
for (const url in spec.paths) {
|
|
254
|
-
for (const method in spec.paths[url]) {
|
|
255
|
-
const operation = spec.paths[url][method];
|
|
256
|
-
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
257
|
-
if (authArray && authArray.length > 0) {
|
|
258
|
-
const currentAuth = authArray[0][0];
|
|
259
|
-
authMap[operation.operationId] = currentAuth;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return authMap;
|
|
264
|
-
}
|
|
265
246
|
static getAuthInfo(spec) {
|
|
266
247
|
let authInfo = undefined;
|
|
267
248
|
for (const url in spec.paths) {
|
|
@@ -290,32 +271,26 @@ class Utils {
|
|
|
290
271
|
let multipleMediaType = false;
|
|
291
272
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
292
273
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
293
|
-
if (
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
static getJsonContentType(responseObject) {
|
|
310
|
-
if (responseObject.content) {
|
|
311
|
-
for (const contentType of Object.keys(responseObject.content)) {
|
|
312
|
-
// json media type can also be "application/json; charset=utf-8"
|
|
313
|
-
if (contentType.indexOf("application/json") >= 0) {
|
|
314
|
-
return responseObject.content[contentType];
|
|
274
|
+
if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
|
|
275
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
276
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
277
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
278
|
+
multipleMediaType = false;
|
|
279
|
+
json = responseObject.content[contentType];
|
|
280
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
281
|
+
multipleMediaType = true;
|
|
282
|
+
if (!allowMultipleMediaType) {
|
|
283
|
+
json = {};
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
return { json, multipleMediaType };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
315
290
|
}
|
|
316
291
|
}
|
|
317
292
|
}
|
|
318
|
-
return {};
|
|
293
|
+
return { json, multipleMediaType };
|
|
319
294
|
}
|
|
320
295
|
static convertPathToCamelCase(path) {
|
|
321
296
|
const pathSegments = path.split(/[./{]/);
|
|
@@ -352,7 +327,7 @@ class Utils {
|
|
|
352
327
|
}
|
|
353
328
|
return newStr;
|
|
354
329
|
}
|
|
355
|
-
static checkServerUrl(servers
|
|
330
|
+
static checkServerUrl(servers) {
|
|
356
331
|
const errors = [];
|
|
357
332
|
let serverUrl;
|
|
358
333
|
try {
|
|
@@ -375,7 +350,8 @@ class Utils {
|
|
|
375
350
|
data: servers,
|
|
376
351
|
});
|
|
377
352
|
}
|
|
378
|
-
else if (protocol !== "https:"
|
|
353
|
+
else if (protocol !== "https:") {
|
|
354
|
+
// Http server url is not supported
|
|
379
355
|
const protocolString = protocol.slice(0, -1);
|
|
380
356
|
errors.push({
|
|
381
357
|
type: ErrorType.UrlProtocolNotSupported,
|
|
@@ -391,11 +367,10 @@ class Utils {
|
|
|
391
367
|
let hasTopLevelServers = false;
|
|
392
368
|
let hasPathLevelServers = false;
|
|
393
369
|
let hasOperationLevelServers = false;
|
|
394
|
-
const allowHttp = options.projectType === ProjectType.Copilot;
|
|
395
370
|
if (spec.servers && spec.servers.length >= 1) {
|
|
396
371
|
hasTopLevelServers = true;
|
|
397
372
|
// for multiple server, we only use the first url
|
|
398
|
-
const serverErrors = Utils.checkServerUrl(spec.servers
|
|
373
|
+
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
399
374
|
errors.push(...serverErrors);
|
|
400
375
|
}
|
|
401
376
|
const paths = spec.paths;
|
|
@@ -403,7 +378,7 @@ class Utils {
|
|
|
403
378
|
const methods = paths[path];
|
|
404
379
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
405
380
|
hasPathLevelServers = true;
|
|
406
|
-
const serverErrors = Utils.checkServerUrl(methods.servers
|
|
381
|
+
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
407
382
|
errors.push(...serverErrors);
|
|
408
383
|
}
|
|
409
384
|
for (const method in methods) {
|
|
@@ -411,7 +386,7 @@ class Utils {
|
|
|
411
386
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
412
387
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
413
388
|
hasOperationLevelServers = true;
|
|
414
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers
|
|
389
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
415
390
|
errors.push(...serverErrors);
|
|
416
391
|
}
|
|
417
392
|
}
|
|
@@ -700,6 +675,22 @@ class Validator {
|
|
|
700
675
|
}
|
|
701
676
|
return result;
|
|
702
677
|
}
|
|
678
|
+
validateResponse(method, path) {
|
|
679
|
+
const result = { isValid: true, reason: [] };
|
|
680
|
+
const operationObject = this.spec.paths[path][method];
|
|
681
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
682
|
+
if (this.options.projectType === ProjectType.SME) {
|
|
683
|
+
// only support response body only contains “application/json” content type
|
|
684
|
+
if (multipleMediaType) {
|
|
685
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
686
|
+
}
|
|
687
|
+
else if (Object.keys(json).length === 0) {
|
|
688
|
+
// response body should not be empty
|
|
689
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return result;
|
|
693
|
+
}
|
|
703
694
|
validateServer(method, path) {
|
|
704
695
|
const result = { isValid: true, reason: [] };
|
|
705
696
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -708,8 +699,8 @@ class Validator {
|
|
|
708
699
|
result.reason.push(ErrorType.NoServerInformation);
|
|
709
700
|
}
|
|
710
701
|
else {
|
|
711
|
-
|
|
712
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]
|
|
702
|
+
// server url should be absolute url with https protocol
|
|
703
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
713
704
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
714
705
|
}
|
|
715
706
|
return result;
|
|
@@ -732,9 +723,6 @@ class Validator {
|
|
|
732
723
|
reason: [ErrorType.MultipleAuthNotSupported],
|
|
733
724
|
};
|
|
734
725
|
}
|
|
735
|
-
if (this.projectType === ProjectType.Copilot) {
|
|
736
|
-
return { isValid: true, reason: [] };
|
|
737
|
-
}
|
|
738
726
|
for (const auths of authSchemeArray) {
|
|
739
727
|
if (auths.length === 1) {
|
|
740
728
|
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
@@ -747,6 +735,114 @@ class Validator {
|
|
|
747
735
|
}
|
|
748
736
|
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
749
737
|
}
|
|
738
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
739
|
+
var _a;
|
|
740
|
+
const paramResult = {
|
|
741
|
+
requiredNum: 0,
|
|
742
|
+
optionalNum: 0,
|
|
743
|
+
isValid: true,
|
|
744
|
+
reason: [],
|
|
745
|
+
};
|
|
746
|
+
if (Object.keys(schema).length === 0) {
|
|
747
|
+
return paramResult;
|
|
748
|
+
}
|
|
749
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
750
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
751
|
+
if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
|
|
752
|
+
paramResult.isValid = false;
|
|
753
|
+
paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
|
|
754
|
+
return paramResult;
|
|
755
|
+
}
|
|
756
|
+
if (schema.type === "string" ||
|
|
757
|
+
schema.type === "integer" ||
|
|
758
|
+
schema.type === "boolean" ||
|
|
759
|
+
schema.type === "number") {
|
|
760
|
+
if (isRequiredWithoutDefault) {
|
|
761
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
762
|
+
}
|
|
763
|
+
else {
|
|
764
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
768
|
+
const { properties } = schema;
|
|
769
|
+
for (const property in properties) {
|
|
770
|
+
let isRequired = false;
|
|
771
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
772
|
+
isRequired = true;
|
|
773
|
+
}
|
|
774
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
775
|
+
paramResult.requiredNum += result.requiredNum;
|
|
776
|
+
paramResult.optionalNum += result.optionalNum;
|
|
777
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
778
|
+
paramResult.reason.push(...result.reason);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
else {
|
|
782
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
783
|
+
paramResult.isValid = false;
|
|
784
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return paramResult;
|
|
788
|
+
}
|
|
789
|
+
checkParamSchema(paramObject) {
|
|
790
|
+
const paramResult = {
|
|
791
|
+
requiredNum: 0,
|
|
792
|
+
optionalNum: 0,
|
|
793
|
+
isValid: true,
|
|
794
|
+
reason: [],
|
|
795
|
+
};
|
|
796
|
+
if (!paramObject) {
|
|
797
|
+
return paramResult;
|
|
798
|
+
}
|
|
799
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
800
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
801
|
+
const param = paramObject[i];
|
|
802
|
+
const schema = param.schema;
|
|
803
|
+
if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
|
|
804
|
+
paramResult.isValid = false;
|
|
805
|
+
paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
809
|
+
if (isCopilot) {
|
|
810
|
+
if (isRequiredWithoutDefault) {
|
|
811
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
812
|
+
}
|
|
813
|
+
else {
|
|
814
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
815
|
+
}
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
819
|
+
if (isRequiredWithoutDefault) {
|
|
820
|
+
paramResult.isValid = false;
|
|
821
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
822
|
+
}
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
if (schema.type !== "boolean" &&
|
|
826
|
+
schema.type !== "string" &&
|
|
827
|
+
schema.type !== "number" &&
|
|
828
|
+
schema.type !== "integer") {
|
|
829
|
+
if (isRequiredWithoutDefault) {
|
|
830
|
+
paramResult.isValid = false;
|
|
831
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
832
|
+
}
|
|
833
|
+
continue;
|
|
834
|
+
}
|
|
835
|
+
if (param.in === "query" || param.in === "path") {
|
|
836
|
+
if (isRequiredWithoutDefault) {
|
|
837
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return paramResult;
|
|
845
|
+
}
|
|
750
846
|
}
|
|
751
847
|
|
|
752
848
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -756,6 +852,7 @@ class CopilotValidator extends Validator {
|
|
|
756
852
|
this.projectType = ProjectType.Copilot;
|
|
757
853
|
this.options = options;
|
|
758
854
|
this.spec = spec;
|
|
855
|
+
this.checkCircularReference();
|
|
759
856
|
}
|
|
760
857
|
validateSpec() {
|
|
761
858
|
const result = { errors: [], warnings: [] };
|
|
@@ -781,6 +878,10 @@ class CopilotValidator extends Validator {
|
|
|
781
878
|
if (!methodAndPathResult.isValid) {
|
|
782
879
|
return methodAndPathResult;
|
|
783
880
|
}
|
|
881
|
+
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
882
|
+
if (!circularReferenceResult.isValid) {
|
|
883
|
+
return circularReferenceResult;
|
|
884
|
+
}
|
|
784
885
|
const operationObject = this.spec.paths[path][method];
|
|
785
886
|
// validate auth
|
|
786
887
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -792,6 +893,24 @@ class CopilotValidator extends Validator {
|
|
|
792
893
|
// validate server
|
|
793
894
|
const validateServerResult = this.validateServer(method, path);
|
|
794
895
|
result.reason.push(...validateServerResult.reason);
|
|
896
|
+
// validate response
|
|
897
|
+
const validateResponseResult = this.validateResponse(method, path);
|
|
898
|
+
result.reason.push(...validateResponseResult.reason);
|
|
899
|
+
// validate requestBody
|
|
900
|
+
const requestBody = operationObject.requestBody;
|
|
901
|
+
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
902
|
+
if (requestJsonBody) {
|
|
903
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
904
|
+
if (!Utils.isObjectSchema(requestBodySchema)) {
|
|
905
|
+
result.reason.push(ErrorType.PostBodySchemaIsNotJson);
|
|
906
|
+
}
|
|
907
|
+
const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
908
|
+
result.reason.push(...requestBodyParamResult.reason);
|
|
909
|
+
}
|
|
910
|
+
// validate parameters
|
|
911
|
+
const paramObject = operationObject.parameters;
|
|
912
|
+
const paramResult = this.checkParamSchema(paramObject);
|
|
913
|
+
result.reason.push(...paramResult.reason);
|
|
795
914
|
if (result.reason.length > 0) {
|
|
796
915
|
result.isValid = false;
|
|
797
916
|
}
|
|
@@ -883,108 +1002,6 @@ class SMEValidator extends Validator {
|
|
|
883
1002
|
}
|
|
884
1003
|
return result;
|
|
885
1004
|
}
|
|
886
|
-
validateResponse(method, path) {
|
|
887
|
-
const result = { isValid: true, reason: [] };
|
|
888
|
-
const operationObject = this.spec.paths[path][method];
|
|
889
|
-
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
890
|
-
// only support response body only contains “application/json” content type
|
|
891
|
-
if (multipleMediaType) {
|
|
892
|
-
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
893
|
-
}
|
|
894
|
-
else if (Object.keys(json).length === 0) {
|
|
895
|
-
// response body should not be empty
|
|
896
|
-
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
897
|
-
}
|
|
898
|
-
return result;
|
|
899
|
-
}
|
|
900
|
-
checkPostBodySchema(schema, isRequired = false) {
|
|
901
|
-
var _a;
|
|
902
|
-
const paramResult = {
|
|
903
|
-
requiredNum: 0,
|
|
904
|
-
optionalNum: 0,
|
|
905
|
-
isValid: true,
|
|
906
|
-
reason: [],
|
|
907
|
-
};
|
|
908
|
-
if (Object.keys(schema).length === 0) {
|
|
909
|
-
return paramResult;
|
|
910
|
-
}
|
|
911
|
-
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
912
|
-
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
913
|
-
if (schema.type === "string" ||
|
|
914
|
-
schema.type === "integer" ||
|
|
915
|
-
schema.type === "boolean" ||
|
|
916
|
-
schema.type === "number") {
|
|
917
|
-
if (isRequiredWithoutDefault) {
|
|
918
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
919
|
-
}
|
|
920
|
-
else {
|
|
921
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
else if (Utils.isObjectSchema(schema)) {
|
|
925
|
-
const { properties } = schema;
|
|
926
|
-
for (const property in properties) {
|
|
927
|
-
let isRequired = false;
|
|
928
|
-
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
929
|
-
isRequired = true;
|
|
930
|
-
}
|
|
931
|
-
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
932
|
-
paramResult.requiredNum += result.requiredNum;
|
|
933
|
-
paramResult.optionalNum += result.optionalNum;
|
|
934
|
-
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
935
|
-
paramResult.reason.push(...result.reason);
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
else {
|
|
939
|
-
if (isRequiredWithoutDefault && !isCopilot) {
|
|
940
|
-
paramResult.isValid = false;
|
|
941
|
-
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
return paramResult;
|
|
945
|
-
}
|
|
946
|
-
checkParamSchema(paramObject) {
|
|
947
|
-
const paramResult = {
|
|
948
|
-
requiredNum: 0,
|
|
949
|
-
optionalNum: 0,
|
|
950
|
-
isValid: true,
|
|
951
|
-
reason: [],
|
|
952
|
-
};
|
|
953
|
-
if (!paramObject) {
|
|
954
|
-
return paramResult;
|
|
955
|
-
}
|
|
956
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
957
|
-
const param = paramObject[i];
|
|
958
|
-
const schema = param.schema;
|
|
959
|
-
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
960
|
-
if (param.in === "header" || param.in === "cookie") {
|
|
961
|
-
if (isRequiredWithoutDefault) {
|
|
962
|
-
paramResult.isValid = false;
|
|
963
|
-
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
964
|
-
}
|
|
965
|
-
continue;
|
|
966
|
-
}
|
|
967
|
-
if (schema.type !== "boolean" &&
|
|
968
|
-
schema.type !== "string" &&
|
|
969
|
-
schema.type !== "number" &&
|
|
970
|
-
schema.type !== "integer") {
|
|
971
|
-
if (isRequiredWithoutDefault) {
|
|
972
|
-
paramResult.isValid = false;
|
|
973
|
-
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
974
|
-
}
|
|
975
|
-
continue;
|
|
976
|
-
}
|
|
977
|
-
if (param.in === "query" || param.in === "path") {
|
|
978
|
-
if (isRequiredWithoutDefault) {
|
|
979
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
980
|
-
}
|
|
981
|
-
else {
|
|
982
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
return paramResult;
|
|
987
|
-
}
|
|
988
1005
|
validateParamCount(postBodyResult, paramResult) {
|
|
989
1006
|
const result = { isValid: true, reason: [] };
|
|
990
1007
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|