@microsoft/m365-spec-parser 0.2.5-rc.1 → 0.2.6-alpha.068057a13.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 +214 -196
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +482 -282
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +214 -196
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +490 -282
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +5 -6
- package/dist/src/index.d.ts +1 -1
- package/dist/src/interfaces.d.ts +18 -4
- package/dist/src/manifestUpdater.d.ts +3 -3
- package/dist/src/specParser.d.ts +12 -2
- package/dist/src/utils.d.ts +7 -3
- package/package.json +3 -4
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";
|
|
@@ -44,6 +41,7 @@ var ErrorType;
|
|
|
44
41
|
ErrorType["UrlPathNotExist"] = "url-path-not-exist";
|
|
45
42
|
ErrorType["Cancelled"] = "cancelled";
|
|
46
43
|
ErrorType["Unknown"] = "unknown";
|
|
44
|
+
ErrorType["AddAuthFailed"] = "add-auth-failed";
|
|
47
45
|
})(ErrorType || (ErrorType = {}));
|
|
48
46
|
/**
|
|
49
47
|
* An enum that represents the types of warnings that can occur during validation.
|
|
@@ -56,6 +54,7 @@ var WarningType;
|
|
|
56
54
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
57
55
|
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
58
56
|
WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
|
|
57
|
+
WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
|
|
59
58
|
WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
60
59
|
WarningType["Unknown"] = "unknown";
|
|
61
60
|
})(WarningType || (WarningType = {}));
|
|
@@ -73,7 +72,12 @@ var ProjectType;
|
|
|
73
72
|
ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
|
|
74
73
|
ProjectType[ProjectType["SME"] = 1] = "SME";
|
|
75
74
|
ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
|
|
76
|
-
})(ProjectType || (ProjectType = {}));
|
|
75
|
+
})(ProjectType || (ProjectType = {}));
|
|
76
|
+
var AdaptiveCardUpdateStrategy;
|
|
77
|
+
(function (AdaptiveCardUpdateStrategy) {
|
|
78
|
+
AdaptiveCardUpdateStrategy[AdaptiveCardUpdateStrategy["CreateNew"] = 0] = "CreateNew";
|
|
79
|
+
AdaptiveCardUpdateStrategy[AdaptiveCardUpdateStrategy["KeepExisting"] = 1] = "KeepExisting";
|
|
80
|
+
})(AdaptiveCardUpdateStrategy || (AdaptiveCardUpdateStrategy = {}));
|
|
77
81
|
|
|
78
82
|
// Copyright (c) Microsoft Corporation.
|
|
79
83
|
class SpecParserError extends Error {
|
|
@@ -103,26 +107,22 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
|
|
|
103
107
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
104
108
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
105
109
|
ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
|
|
110
|
+
ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
|
|
106
111
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
107
112
|
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.";
|
|
108
113
|
ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
|
|
109
|
-
ConstantString.WrappedCardVersion = "
|
|
110
|
-
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/
|
|
114
|
+
ConstantString.WrappedCardVersion = "1.0";
|
|
115
|
+
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/v1.19/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
111
116
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
112
117
|
ConstantString.GetMethod = "get";
|
|
113
118
|
ConstantString.PostMethod = "post";
|
|
114
119
|
ConstantString.AdaptiveCardVersion = "1.5";
|
|
115
|
-
ConstantString.AdaptiveCardSchema = "
|
|
120
|
+
ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
|
|
116
121
|
ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
117
122
|
ConstantString.TextBlockType = "TextBlock";
|
|
118
123
|
ConstantString.ImageType = "Image";
|
|
119
124
|
ConstantString.ContainerType = "Container";
|
|
120
|
-
ConstantString.RegistrationIdPostfix =
|
|
121
|
-
apiKey: "REGISTRATION_ID",
|
|
122
|
-
oauth2: "CONFIGURATION_ID",
|
|
123
|
-
http: "REGISTRATION_ID",
|
|
124
|
-
openIdConnect: "REGISTRATION_ID",
|
|
125
|
-
};
|
|
125
|
+
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
126
126
|
ConstantString.ResponseCodeFor20X = [
|
|
127
127
|
"200",
|
|
128
128
|
"201",
|
|
@@ -134,6 +134,7 @@ ConstantString.ResponseCodeFor20X = [
|
|
|
134
134
|
"207",
|
|
135
135
|
"208",
|
|
136
136
|
"226",
|
|
137
|
+
"2XX",
|
|
137
138
|
"default",
|
|
138
139
|
];
|
|
139
140
|
ConstantString.AllOperationMethods = [
|
|
@@ -191,17 +192,6 @@ ConstantString.PluginManifestSchema = "https://developer.microsoft.com/json-sche
|
|
|
191
192
|
|
|
192
193
|
// Copyright (c) Microsoft Corporation.
|
|
193
194
|
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
|
-
}
|
|
205
195
|
static isObjectSchema(schema) {
|
|
206
196
|
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
207
197
|
}
|
|
@@ -214,11 +204,32 @@ class Utils {
|
|
|
214
204
|
static isAPIKeyAuth(authScheme) {
|
|
215
205
|
return authScheme.type === "apiKey";
|
|
216
206
|
}
|
|
207
|
+
static isAPIKeyAuthButNotInCookie(authScheme) {
|
|
208
|
+
return authScheme.type === "apiKey" && authScheme.in !== "cookie";
|
|
209
|
+
}
|
|
217
210
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
218
211
|
return !!(authScheme.type === "oauth2" &&
|
|
219
212
|
authScheme.flows &&
|
|
220
213
|
authScheme.flows.authorizationCode);
|
|
221
214
|
}
|
|
215
|
+
static isNotSupportedAuth(authSchemeArray) {
|
|
216
|
+
if (authSchemeArray.length === 0) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
for (const auths of authSchemeArray) {
|
|
223
|
+
if (auths.length === 1) {
|
|
224
|
+
if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
|
|
225
|
+
Utils.isBearerTokenAuth(auths[0].authScheme) ||
|
|
226
|
+
Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
222
233
|
static getAuthArray(securities, spec) {
|
|
223
234
|
var _a;
|
|
224
235
|
const result = [];
|
|
@@ -243,6 +254,20 @@ class Utils {
|
|
|
243
254
|
result.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
244
255
|
return result;
|
|
245
256
|
}
|
|
257
|
+
static getAuthMap(spec) {
|
|
258
|
+
const authMap = {};
|
|
259
|
+
for (const url in spec.paths) {
|
|
260
|
+
for (const method in spec.paths[url]) {
|
|
261
|
+
const operation = spec.paths[url][method];
|
|
262
|
+
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
263
|
+
if (authArray && authArray.length > 0) {
|
|
264
|
+
const currentAuth = authArray[0][0];
|
|
265
|
+
authMap[operation.operationId] = currentAuth;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return authMap;
|
|
270
|
+
}
|
|
246
271
|
static getAuthInfo(spec) {
|
|
247
272
|
let authInfo = undefined;
|
|
248
273
|
for (const url in spec.paths) {
|
|
@@ -271,27 +296,33 @@ class Utils {
|
|
|
271
296
|
let multipleMediaType = false;
|
|
272
297
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
273
298
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
274
|
-
if (responseObject
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
else {
|
|
287
|
-
return { json, multipleMediaType };
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
299
|
+
if (!responseObject) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
|
|
303
|
+
if (!allowMultipleMediaType && multipleMediaType) {
|
|
304
|
+
json = {};
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const mediaObj = Utils.getJsonContentType(responseObject);
|
|
308
|
+
if (Object.keys(mediaObj).length > 0) {
|
|
309
|
+
json = mediaObj;
|
|
310
|
+
return { json, multipleMediaType };
|
|
291
311
|
}
|
|
292
312
|
}
|
|
293
313
|
return { json, multipleMediaType };
|
|
294
314
|
}
|
|
315
|
+
static getJsonContentType(responseObject) {
|
|
316
|
+
if (responseObject.content) {
|
|
317
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
318
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
319
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
320
|
+
return responseObject.content[contentType];
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return {};
|
|
325
|
+
}
|
|
295
326
|
static convertPathToCamelCase(path) {
|
|
296
327
|
const pathSegments = path.split(/[./{]/);
|
|
297
328
|
const camelCaseSegments = pathSegments.map((segment) => {
|
|
@@ -327,7 +358,7 @@ class Utils {
|
|
|
327
358
|
}
|
|
328
359
|
return newStr;
|
|
329
360
|
}
|
|
330
|
-
static checkServerUrl(servers) {
|
|
361
|
+
static checkServerUrl(servers, allowHttp = false) {
|
|
331
362
|
const errors = [];
|
|
332
363
|
let serverUrl;
|
|
333
364
|
try {
|
|
@@ -350,8 +381,7 @@ class Utils {
|
|
|
350
381
|
data: servers,
|
|
351
382
|
});
|
|
352
383
|
}
|
|
353
|
-
else if (protocol !== "https:") {
|
|
354
|
-
// Http server url is not supported
|
|
384
|
+
else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
|
|
355
385
|
const protocolString = protocol.slice(0, -1);
|
|
356
386
|
errors.push({
|
|
357
387
|
type: ErrorType.UrlProtocolNotSupported,
|
|
@@ -367,10 +397,11 @@ class Utils {
|
|
|
367
397
|
let hasTopLevelServers = false;
|
|
368
398
|
let hasPathLevelServers = false;
|
|
369
399
|
let hasOperationLevelServers = false;
|
|
400
|
+
const allowHttp = options.projectType === ProjectType.Copilot;
|
|
370
401
|
if (spec.servers && spec.servers.length >= 1) {
|
|
371
402
|
hasTopLevelServers = true;
|
|
372
403
|
// for multiple server, we only use the first url
|
|
373
|
-
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
404
|
+
const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
|
|
374
405
|
errors.push(...serverErrors);
|
|
375
406
|
}
|
|
376
407
|
const paths = spec.paths;
|
|
@@ -378,7 +409,7 @@ class Utils {
|
|
|
378
409
|
const methods = paths[path];
|
|
379
410
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
380
411
|
hasPathLevelServers = true;
|
|
381
|
-
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
412
|
+
const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
|
|
382
413
|
errors.push(...serverErrors);
|
|
383
414
|
}
|
|
384
415
|
for (const method in methods) {
|
|
@@ -386,7 +417,7 @@ class Utils {
|
|
|
386
417
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
387
418
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
388
419
|
hasOperationLevelServers = true;
|
|
389
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
420
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
|
|
390
421
|
errors.push(...serverErrors);
|
|
391
422
|
}
|
|
392
423
|
}
|
|
@@ -547,6 +578,35 @@ class Utils {
|
|
|
547
578
|
const serverUrl = operationServer || methodServer || rootServer;
|
|
548
579
|
return serverUrl;
|
|
549
580
|
}
|
|
581
|
+
static getAuthSchemaObject(authType, authParameters) {
|
|
582
|
+
switch (authType) {
|
|
583
|
+
case "oauth":
|
|
584
|
+
case "microsoft-entra":
|
|
585
|
+
return {
|
|
586
|
+
type: "oauth2",
|
|
587
|
+
flows: {
|
|
588
|
+
authorizationCode: {
|
|
589
|
+
authorizationUrl: authParameters.authorizationUrl,
|
|
590
|
+
tokenUrl: authParameters.tokenUrl,
|
|
591
|
+
refreshUrl: authParameters.refreshUrl,
|
|
592
|
+
scopes: authParameters.scopes,
|
|
593
|
+
},
|
|
594
|
+
},
|
|
595
|
+
};
|
|
596
|
+
case "api-key":
|
|
597
|
+
return {
|
|
598
|
+
type: "apiKey",
|
|
599
|
+
in: authParameters.in,
|
|
600
|
+
name: authParameters.name,
|
|
601
|
+
};
|
|
602
|
+
case "bearer-token":
|
|
603
|
+
default:
|
|
604
|
+
return {
|
|
605
|
+
type: "http",
|
|
606
|
+
scheme: "bearer",
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
}
|
|
550
610
|
}
|
|
551
611
|
|
|
552
612
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -675,22 +735,6 @@ class Validator {
|
|
|
675
735
|
}
|
|
676
736
|
return result;
|
|
677
737
|
}
|
|
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
|
-
}
|
|
694
738
|
validateServer(method, path) {
|
|
695
739
|
const result = { isValid: true, reason: [] };
|
|
696
740
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -699,8 +743,8 @@ class Validator {
|
|
|
699
743
|
result.reason.push(ErrorType.NoServerInformation);
|
|
700
744
|
}
|
|
701
745
|
else {
|
|
702
|
-
|
|
703
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
746
|
+
const allowHttp = this.projectType === ProjectType.Copilot;
|
|
747
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
|
|
704
748
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
705
749
|
}
|
|
706
750
|
return result;
|
|
@@ -723,6 +767,9 @@ class Validator {
|
|
|
723
767
|
reason: [ErrorType.MultipleAuthNotSupported],
|
|
724
768
|
};
|
|
725
769
|
}
|
|
770
|
+
if (this.projectType === ProjectType.Copilot) {
|
|
771
|
+
return { isValid: true, reason: [] };
|
|
772
|
+
}
|
|
726
773
|
for (const auths of authSchemeArray) {
|
|
727
774
|
if (auths.length === 1) {
|
|
728
775
|
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
@@ -735,114 +782,6 @@ class Validator {
|
|
|
735
782
|
}
|
|
736
783
|
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
737
784
|
}
|
|
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
|
-
}
|
|
846
785
|
}
|
|
847
786
|
|
|
848
787
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -852,7 +791,6 @@ class CopilotValidator extends Validator {
|
|
|
852
791
|
this.projectType = ProjectType.Copilot;
|
|
853
792
|
this.options = options;
|
|
854
793
|
this.spec = spec;
|
|
855
|
-
this.checkCircularReference();
|
|
856
794
|
}
|
|
857
795
|
validateSpec() {
|
|
858
796
|
const result = { errors: [], warnings: [] };
|
|
@@ -878,10 +816,6 @@ class CopilotValidator extends Validator {
|
|
|
878
816
|
if (!methodAndPathResult.isValid) {
|
|
879
817
|
return methodAndPathResult;
|
|
880
818
|
}
|
|
881
|
-
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
882
|
-
if (!circularReferenceResult.isValid) {
|
|
883
|
-
return circularReferenceResult;
|
|
884
|
-
}
|
|
885
819
|
const operationObject = this.spec.paths[path][method];
|
|
886
820
|
// validate auth
|
|
887
821
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -893,24 +827,6 @@ class CopilotValidator extends Validator {
|
|
|
893
827
|
// validate server
|
|
894
828
|
const validateServerResult = this.validateServer(method, path);
|
|
895
829
|
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);
|
|
914
830
|
if (result.reason.length > 0) {
|
|
915
831
|
result.isValid = false;
|
|
916
832
|
}
|
|
@@ -1002,6 +918,108 @@ class SMEValidator extends Validator {
|
|
|
1002
918
|
}
|
|
1003
919
|
return result;
|
|
1004
920
|
}
|
|
921
|
+
validateResponse(method, path) {
|
|
922
|
+
const result = { isValid: true, reason: [] };
|
|
923
|
+
const operationObject = this.spec.paths[path][method];
|
|
924
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
925
|
+
// only support response body only contains “application/json” content type
|
|
926
|
+
if (multipleMediaType) {
|
|
927
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
928
|
+
}
|
|
929
|
+
else if (Object.keys(json).length === 0) {
|
|
930
|
+
// response body should not be empty
|
|
931
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
932
|
+
}
|
|
933
|
+
return result;
|
|
934
|
+
}
|
|
935
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
936
|
+
var _a;
|
|
937
|
+
const paramResult = {
|
|
938
|
+
requiredNum: 0,
|
|
939
|
+
optionalNum: 0,
|
|
940
|
+
isValid: true,
|
|
941
|
+
reason: [],
|
|
942
|
+
};
|
|
943
|
+
if (Object.keys(schema).length === 0) {
|
|
944
|
+
return paramResult;
|
|
945
|
+
}
|
|
946
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
947
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
948
|
+
if (schema.type === "string" ||
|
|
949
|
+
schema.type === "integer" ||
|
|
950
|
+
schema.type === "boolean" ||
|
|
951
|
+
schema.type === "number") {
|
|
952
|
+
if (isRequiredWithoutDefault) {
|
|
953
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
960
|
+
const { properties } = schema;
|
|
961
|
+
for (const property in properties) {
|
|
962
|
+
let isRequired = false;
|
|
963
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
964
|
+
isRequired = true;
|
|
965
|
+
}
|
|
966
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
967
|
+
paramResult.requiredNum += result.requiredNum;
|
|
968
|
+
paramResult.optionalNum += result.optionalNum;
|
|
969
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
970
|
+
paramResult.reason.push(...result.reason);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
else {
|
|
974
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
975
|
+
paramResult.isValid = false;
|
|
976
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return paramResult;
|
|
980
|
+
}
|
|
981
|
+
checkParamSchema(paramObject) {
|
|
982
|
+
const paramResult = {
|
|
983
|
+
requiredNum: 0,
|
|
984
|
+
optionalNum: 0,
|
|
985
|
+
isValid: true,
|
|
986
|
+
reason: [],
|
|
987
|
+
};
|
|
988
|
+
if (!paramObject) {
|
|
989
|
+
return paramResult;
|
|
990
|
+
}
|
|
991
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
992
|
+
const param = paramObject[i];
|
|
993
|
+
const schema = param.schema;
|
|
994
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
995
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
996
|
+
if (isRequiredWithoutDefault) {
|
|
997
|
+
paramResult.isValid = false;
|
|
998
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
999
|
+
}
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
1002
|
+
if (schema.type !== "boolean" &&
|
|
1003
|
+
schema.type !== "string" &&
|
|
1004
|
+
schema.type !== "number" &&
|
|
1005
|
+
schema.type !== "integer") {
|
|
1006
|
+
if (isRequiredWithoutDefault) {
|
|
1007
|
+
paramResult.isValid = false;
|
|
1008
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
1009
|
+
}
|
|
1010
|
+
continue;
|
|
1011
|
+
}
|
|
1012
|
+
if (param.in === "query" || param.in === "path") {
|
|
1013
|
+
if (isRequiredWithoutDefault) {
|
|
1014
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
1015
|
+
}
|
|
1016
|
+
else {
|
|
1017
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
return paramResult;
|
|
1022
|
+
}
|
|
1005
1023
|
validateParamCount(postBodyResult, paramResult) {
|
|
1006
1024
|
const result = { isValid: true, reason: [] };
|
|
1007
1025
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|