@microsoft/m365-spec-parser 0.2.5 → 0.2.6-alpha.0b985f7da.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 +176 -193
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +341 -274
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +176 -193
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +346 -275
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +3 -4
- package/dist/src/interfaces.d.ts +10 -3
- package/dist/src/manifestUpdater.d.ts +3 -3
- package/dist/src/specParser.d.ts +7 -0
- package/dist/src/utils.d.ts +6 -3
- package/package.json +3 -4
package/dist/index.esm2017.mjs
CHANGED
|
@@ -38,11 +38,8 @@ var ErrorType;
|
|
|
38
38
|
ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
|
|
39
39
|
ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
|
|
40
40
|
ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
|
|
41
|
-
ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
|
|
42
41
|
ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
|
|
43
42
|
ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
|
|
44
|
-
ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
|
|
45
|
-
ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
|
|
46
43
|
ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
|
|
47
44
|
ErrorType["NoParameter"] = "no-parameter";
|
|
48
45
|
ErrorType["NoAPIInfo"] = "no-api-info";
|
|
@@ -62,6 +59,7 @@ var WarningType;
|
|
|
62
59
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
63
60
|
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
64
61
|
WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
|
|
62
|
+
WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
|
|
65
63
|
WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
66
64
|
WarningType["Unknown"] = "unknown";
|
|
67
65
|
})(WarningType || (WarningType = {}));
|
|
@@ -101,6 +99,7 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
|
|
|
101
99
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
102
100
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
103
101
|
ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
|
|
102
|
+
ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
|
|
104
103
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
105
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.";
|
|
106
105
|
ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
|
|
@@ -110,17 +109,12 @@ ConstantString.WrappedCardResponseLayout = "list";
|
|
|
110
109
|
ConstantString.GetMethod = "get";
|
|
111
110
|
ConstantString.PostMethod = "post";
|
|
112
111
|
ConstantString.AdaptiveCardVersion = "1.5";
|
|
113
|
-
ConstantString.AdaptiveCardSchema = "
|
|
112
|
+
ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
|
|
114
113
|
ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
115
114
|
ConstantString.TextBlockType = "TextBlock";
|
|
116
115
|
ConstantString.ImageType = "Image";
|
|
117
116
|
ConstantString.ContainerType = "Container";
|
|
118
|
-
ConstantString.RegistrationIdPostfix =
|
|
119
|
-
apiKey: "REGISTRATION_ID",
|
|
120
|
-
oauth2: "CONFIGURATION_ID",
|
|
121
|
-
http: "REGISTRATION_ID",
|
|
122
|
-
openIdConnect: "REGISTRATION_ID",
|
|
123
|
-
};
|
|
117
|
+
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
124
118
|
ConstantString.ResponseCodeFor20X = [
|
|
125
119
|
"200",
|
|
126
120
|
"201",
|
|
@@ -132,6 +126,7 @@ ConstantString.ResponseCodeFor20X = [
|
|
|
132
126
|
"207",
|
|
133
127
|
"208",
|
|
134
128
|
"226",
|
|
129
|
+
"2XX",
|
|
135
130
|
"default",
|
|
136
131
|
];
|
|
137
132
|
ConstantString.AllOperationMethods = [
|
|
@@ -197,17 +192,6 @@ class SpecParserError extends Error {
|
|
|
197
192
|
|
|
198
193
|
// Copyright (c) Microsoft Corporation.
|
|
199
194
|
class Utils {
|
|
200
|
-
static hasNestedObjectInSchema(schema) {
|
|
201
|
-
if (this.isObjectSchema(schema)) {
|
|
202
|
-
for (const property in schema.properties) {
|
|
203
|
-
const nestedSchema = schema.properties[property];
|
|
204
|
-
if (this.isObjectSchema(nestedSchema)) {
|
|
205
|
-
return true;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
195
|
static isObjectSchema(schema) {
|
|
212
196
|
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
213
197
|
}
|
|
@@ -220,11 +204,32 @@ class Utils {
|
|
|
220
204
|
static isAPIKeyAuth(authScheme) {
|
|
221
205
|
return authScheme.type === "apiKey";
|
|
222
206
|
}
|
|
207
|
+
static isAPIKeyAuthButNotInCookie(authScheme) {
|
|
208
|
+
return authScheme.type === "apiKey" && authScheme.in !== "cookie";
|
|
209
|
+
}
|
|
223
210
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
224
211
|
return !!(authScheme.type === "oauth2" &&
|
|
225
212
|
authScheme.flows &&
|
|
226
213
|
authScheme.flows.authorizationCode);
|
|
227
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
|
+
}
|
|
228
233
|
static getAuthArray(securities, spec) {
|
|
229
234
|
var _a;
|
|
230
235
|
const result = [];
|
|
@@ -249,6 +254,20 @@ class Utils {
|
|
|
249
254
|
result.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
250
255
|
return result;
|
|
251
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
|
+
}
|
|
252
271
|
static getAuthInfo(spec) {
|
|
253
272
|
let authInfo = undefined;
|
|
254
273
|
for (const url in spec.paths) {
|
|
@@ -277,27 +296,33 @@ class Utils {
|
|
|
277
296
|
let multipleMediaType = false;
|
|
278
297
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
279
298
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
280
|
-
if (responseObject
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
else {
|
|
293
|
-
return { json, multipleMediaType };
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
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 };
|
|
297
311
|
}
|
|
298
312
|
}
|
|
299
313
|
return { json, multipleMediaType };
|
|
300
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
|
+
}
|
|
301
326
|
static convertPathToCamelCase(path) {
|
|
302
327
|
const pathSegments = path.split(/[./{]/);
|
|
303
328
|
const camelCaseSegments = pathSegments.map((segment) => {
|
|
@@ -333,7 +358,7 @@ class Utils {
|
|
|
333
358
|
}
|
|
334
359
|
return newStr;
|
|
335
360
|
}
|
|
336
|
-
static checkServerUrl(servers) {
|
|
361
|
+
static checkServerUrl(servers, allowHttp = false) {
|
|
337
362
|
const errors = [];
|
|
338
363
|
let serverUrl;
|
|
339
364
|
try {
|
|
@@ -356,8 +381,7 @@ class Utils {
|
|
|
356
381
|
data: servers,
|
|
357
382
|
});
|
|
358
383
|
}
|
|
359
|
-
else if (protocol !== "https:") {
|
|
360
|
-
// Http server url is not supported
|
|
384
|
+
else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
|
|
361
385
|
const protocolString = protocol.slice(0, -1);
|
|
362
386
|
errors.push({
|
|
363
387
|
type: ErrorType.UrlProtocolNotSupported,
|
|
@@ -373,10 +397,11 @@ class Utils {
|
|
|
373
397
|
let hasTopLevelServers = false;
|
|
374
398
|
let hasPathLevelServers = false;
|
|
375
399
|
let hasOperationLevelServers = false;
|
|
400
|
+
const allowHttp = options.projectType === ProjectType.Copilot;
|
|
376
401
|
if (spec.servers && spec.servers.length >= 1) {
|
|
377
402
|
hasTopLevelServers = true;
|
|
378
403
|
// for multiple server, we only use the first url
|
|
379
|
-
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
404
|
+
const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
|
|
380
405
|
errors.push(...serverErrors);
|
|
381
406
|
}
|
|
382
407
|
const paths = spec.paths;
|
|
@@ -384,7 +409,7 @@ class Utils {
|
|
|
384
409
|
const methods = paths[path];
|
|
385
410
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
386
411
|
hasPathLevelServers = true;
|
|
387
|
-
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
412
|
+
const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
|
|
388
413
|
errors.push(...serverErrors);
|
|
389
414
|
}
|
|
390
415
|
for (const method in methods) {
|
|
@@ -392,7 +417,7 @@ class Utils {
|
|
|
392
417
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
393
418
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
394
419
|
hasOperationLevelServers = true;
|
|
395
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
420
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
|
|
396
421
|
errors.push(...serverErrors);
|
|
397
422
|
}
|
|
398
423
|
}
|
|
@@ -681,22 +706,6 @@ class Validator {
|
|
|
681
706
|
}
|
|
682
707
|
return result;
|
|
683
708
|
}
|
|
684
|
-
validateResponse(method, path) {
|
|
685
|
-
const result = { isValid: true, reason: [] };
|
|
686
|
-
const operationObject = this.spec.paths[path][method];
|
|
687
|
-
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
688
|
-
if (this.options.projectType === ProjectType.SME) {
|
|
689
|
-
// only support response body only contains “application/json” content type
|
|
690
|
-
if (multipleMediaType) {
|
|
691
|
-
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
692
|
-
}
|
|
693
|
-
else if (Object.keys(json).length === 0) {
|
|
694
|
-
// response body should not be empty
|
|
695
|
-
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
return result;
|
|
699
|
-
}
|
|
700
709
|
validateServer(method, path) {
|
|
701
710
|
const result = { isValid: true, reason: [] };
|
|
702
711
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -705,8 +714,8 @@ class Validator {
|
|
|
705
714
|
result.reason.push(ErrorType.NoServerInformation);
|
|
706
715
|
}
|
|
707
716
|
else {
|
|
708
|
-
|
|
709
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
717
|
+
const allowHttp = this.projectType === ProjectType.Copilot;
|
|
718
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
|
|
710
719
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
711
720
|
}
|
|
712
721
|
return result;
|
|
@@ -729,6 +738,9 @@ class Validator {
|
|
|
729
738
|
reason: [ErrorType.MultipleAuthNotSupported],
|
|
730
739
|
};
|
|
731
740
|
}
|
|
741
|
+
if (this.projectType === ProjectType.Copilot) {
|
|
742
|
+
return { isValid: true, reason: [] };
|
|
743
|
+
}
|
|
732
744
|
for (const auths of authSchemeArray) {
|
|
733
745
|
if (auths.length === 1) {
|
|
734
746
|
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
@@ -741,114 +753,6 @@ class Validator {
|
|
|
741
753
|
}
|
|
742
754
|
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
743
755
|
}
|
|
744
|
-
checkPostBodySchema(schema, isRequired = false) {
|
|
745
|
-
var _a;
|
|
746
|
-
const paramResult = {
|
|
747
|
-
requiredNum: 0,
|
|
748
|
-
optionalNum: 0,
|
|
749
|
-
isValid: true,
|
|
750
|
-
reason: [],
|
|
751
|
-
};
|
|
752
|
-
if (Object.keys(schema).length === 0) {
|
|
753
|
-
return paramResult;
|
|
754
|
-
}
|
|
755
|
-
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
756
|
-
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
757
|
-
if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
|
|
758
|
-
paramResult.isValid = false;
|
|
759
|
-
paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
|
|
760
|
-
return paramResult;
|
|
761
|
-
}
|
|
762
|
-
if (schema.type === "string" ||
|
|
763
|
-
schema.type === "integer" ||
|
|
764
|
-
schema.type === "boolean" ||
|
|
765
|
-
schema.type === "number") {
|
|
766
|
-
if (isRequiredWithoutDefault) {
|
|
767
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
768
|
-
}
|
|
769
|
-
else {
|
|
770
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
else if (Utils.isObjectSchema(schema)) {
|
|
774
|
-
const { properties } = schema;
|
|
775
|
-
for (const property in properties) {
|
|
776
|
-
let isRequired = false;
|
|
777
|
-
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
778
|
-
isRequired = true;
|
|
779
|
-
}
|
|
780
|
-
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
781
|
-
paramResult.requiredNum += result.requiredNum;
|
|
782
|
-
paramResult.optionalNum += result.optionalNum;
|
|
783
|
-
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
784
|
-
paramResult.reason.push(...result.reason);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
else {
|
|
788
|
-
if (isRequiredWithoutDefault && !isCopilot) {
|
|
789
|
-
paramResult.isValid = false;
|
|
790
|
-
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
return paramResult;
|
|
794
|
-
}
|
|
795
|
-
checkParamSchema(paramObject) {
|
|
796
|
-
const paramResult = {
|
|
797
|
-
requiredNum: 0,
|
|
798
|
-
optionalNum: 0,
|
|
799
|
-
isValid: true,
|
|
800
|
-
reason: [],
|
|
801
|
-
};
|
|
802
|
-
if (!paramObject) {
|
|
803
|
-
return paramResult;
|
|
804
|
-
}
|
|
805
|
-
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
806
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
807
|
-
const param = paramObject[i];
|
|
808
|
-
const schema = param.schema;
|
|
809
|
-
if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
|
|
810
|
-
paramResult.isValid = false;
|
|
811
|
-
paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
|
|
812
|
-
continue;
|
|
813
|
-
}
|
|
814
|
-
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
815
|
-
if (isCopilot) {
|
|
816
|
-
if (isRequiredWithoutDefault) {
|
|
817
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
818
|
-
}
|
|
819
|
-
else {
|
|
820
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
821
|
-
}
|
|
822
|
-
continue;
|
|
823
|
-
}
|
|
824
|
-
if (param.in === "header" || param.in === "cookie") {
|
|
825
|
-
if (isRequiredWithoutDefault) {
|
|
826
|
-
paramResult.isValid = false;
|
|
827
|
-
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
828
|
-
}
|
|
829
|
-
continue;
|
|
830
|
-
}
|
|
831
|
-
if (schema.type !== "boolean" &&
|
|
832
|
-
schema.type !== "string" &&
|
|
833
|
-
schema.type !== "number" &&
|
|
834
|
-
schema.type !== "integer") {
|
|
835
|
-
if (isRequiredWithoutDefault) {
|
|
836
|
-
paramResult.isValid = false;
|
|
837
|
-
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
838
|
-
}
|
|
839
|
-
continue;
|
|
840
|
-
}
|
|
841
|
-
if (param.in === "query" || param.in === "path") {
|
|
842
|
-
if (isRequiredWithoutDefault) {
|
|
843
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
844
|
-
}
|
|
845
|
-
else {
|
|
846
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
return paramResult;
|
|
851
|
-
}
|
|
852
756
|
}
|
|
853
757
|
|
|
854
758
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -858,7 +762,6 @@ class CopilotValidator extends Validator {
|
|
|
858
762
|
this.projectType = ProjectType.Copilot;
|
|
859
763
|
this.options = options;
|
|
860
764
|
this.spec = spec;
|
|
861
|
-
this.checkCircularReference();
|
|
862
765
|
}
|
|
863
766
|
validateSpec() {
|
|
864
767
|
const result = { errors: [], warnings: [] };
|
|
@@ -884,10 +787,6 @@ class CopilotValidator extends Validator {
|
|
|
884
787
|
if (!methodAndPathResult.isValid) {
|
|
885
788
|
return methodAndPathResult;
|
|
886
789
|
}
|
|
887
|
-
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
888
|
-
if (!circularReferenceResult.isValid) {
|
|
889
|
-
return circularReferenceResult;
|
|
890
|
-
}
|
|
891
790
|
const operationObject = this.spec.paths[path][method];
|
|
892
791
|
// validate auth
|
|
893
792
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -899,24 +798,6 @@ class CopilotValidator extends Validator {
|
|
|
899
798
|
// validate server
|
|
900
799
|
const validateServerResult = this.validateServer(method, path);
|
|
901
800
|
result.reason.push(...validateServerResult.reason);
|
|
902
|
-
// validate response
|
|
903
|
-
const validateResponseResult = this.validateResponse(method, path);
|
|
904
|
-
result.reason.push(...validateResponseResult.reason);
|
|
905
|
-
// validate requestBody
|
|
906
|
-
const requestBody = operationObject.requestBody;
|
|
907
|
-
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
908
|
-
if (requestJsonBody) {
|
|
909
|
-
const requestBodySchema = requestJsonBody.schema;
|
|
910
|
-
if (!Utils.isObjectSchema(requestBodySchema)) {
|
|
911
|
-
result.reason.push(ErrorType.PostBodySchemaIsNotJson);
|
|
912
|
-
}
|
|
913
|
-
const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
914
|
-
result.reason.push(...requestBodyParamResult.reason);
|
|
915
|
-
}
|
|
916
|
-
// validate parameters
|
|
917
|
-
const paramObject = operationObject.parameters;
|
|
918
|
-
const paramResult = this.checkParamSchema(paramObject);
|
|
919
|
-
result.reason.push(...paramResult.reason);
|
|
920
801
|
if (result.reason.length > 0) {
|
|
921
802
|
result.isValid = false;
|
|
922
803
|
}
|
|
@@ -1008,6 +889,108 @@ class SMEValidator extends Validator {
|
|
|
1008
889
|
}
|
|
1009
890
|
return result;
|
|
1010
891
|
}
|
|
892
|
+
validateResponse(method, path) {
|
|
893
|
+
const result = { isValid: true, reason: [] };
|
|
894
|
+
const operationObject = this.spec.paths[path][method];
|
|
895
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
896
|
+
// only support response body only contains “application/json” content type
|
|
897
|
+
if (multipleMediaType) {
|
|
898
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
899
|
+
}
|
|
900
|
+
else if (Object.keys(json).length === 0) {
|
|
901
|
+
// response body should not be empty
|
|
902
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
903
|
+
}
|
|
904
|
+
return result;
|
|
905
|
+
}
|
|
906
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
907
|
+
var _a;
|
|
908
|
+
const paramResult = {
|
|
909
|
+
requiredNum: 0,
|
|
910
|
+
optionalNum: 0,
|
|
911
|
+
isValid: true,
|
|
912
|
+
reason: [],
|
|
913
|
+
};
|
|
914
|
+
if (Object.keys(schema).length === 0) {
|
|
915
|
+
return paramResult;
|
|
916
|
+
}
|
|
917
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
918
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
919
|
+
if (schema.type === "string" ||
|
|
920
|
+
schema.type === "integer" ||
|
|
921
|
+
schema.type === "boolean" ||
|
|
922
|
+
schema.type === "number") {
|
|
923
|
+
if (isRequiredWithoutDefault) {
|
|
924
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
925
|
+
}
|
|
926
|
+
else {
|
|
927
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
931
|
+
const { properties } = schema;
|
|
932
|
+
for (const property in properties) {
|
|
933
|
+
let isRequired = false;
|
|
934
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
935
|
+
isRequired = true;
|
|
936
|
+
}
|
|
937
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
938
|
+
paramResult.requiredNum += result.requiredNum;
|
|
939
|
+
paramResult.optionalNum += result.optionalNum;
|
|
940
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
941
|
+
paramResult.reason.push(...result.reason);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
946
|
+
paramResult.isValid = false;
|
|
947
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return paramResult;
|
|
951
|
+
}
|
|
952
|
+
checkParamSchema(paramObject) {
|
|
953
|
+
const paramResult = {
|
|
954
|
+
requiredNum: 0,
|
|
955
|
+
optionalNum: 0,
|
|
956
|
+
isValid: true,
|
|
957
|
+
reason: [],
|
|
958
|
+
};
|
|
959
|
+
if (!paramObject) {
|
|
960
|
+
return paramResult;
|
|
961
|
+
}
|
|
962
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
963
|
+
const param = paramObject[i];
|
|
964
|
+
const schema = param.schema;
|
|
965
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
966
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
967
|
+
if (isRequiredWithoutDefault) {
|
|
968
|
+
paramResult.isValid = false;
|
|
969
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
970
|
+
}
|
|
971
|
+
continue;
|
|
972
|
+
}
|
|
973
|
+
if (schema.type !== "boolean" &&
|
|
974
|
+
schema.type !== "string" &&
|
|
975
|
+
schema.type !== "number" &&
|
|
976
|
+
schema.type !== "integer") {
|
|
977
|
+
if (isRequiredWithoutDefault) {
|
|
978
|
+
paramResult.isValid = false;
|
|
979
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
980
|
+
}
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
if (param.in === "query" || param.in === "path") {
|
|
984
|
+
if (isRequiredWithoutDefault) {
|
|
985
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
return paramResult;
|
|
993
|
+
}
|
|
1011
994
|
validateParamCount(postBodyResult, paramResult) {
|
|
1012
995
|
const result = { isValid: true, reason: [] };
|
|
1013
996
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
@@ -1709,7 +1692,7 @@ function inferProperties(card) {
|
|
|
1709
1692
|
|
|
1710
1693
|
// Copyright (c) Microsoft Corporation.
|
|
1711
1694
|
class ManifestUpdater {
|
|
1712
|
-
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options,
|
|
1695
|
+
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authMap, existingPluginManifestInfo) {
|
|
1713
1696
|
const manifest = await fs.readJSON(manifestPath);
|
|
1714
1697
|
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
1715
1698
|
const useCopilotExtensionsInSchema = await ManifestUtil.useCopilotExtensionsInSchema(manifest);
|
|
@@ -1739,7 +1722,7 @@ class ManifestUpdater {
|
|
|
1739
1722
|
}
|
|
1740
1723
|
const appName = this.removeEnvs(manifest.name.short);
|
|
1741
1724
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
1742
|
-
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1725
|
+
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo);
|
|
1743
1726
|
return [manifest, apiPlugin, warnings];
|
|
1744
1727
|
}
|
|
1745
1728
|
static updateManifestDescription(manifest, spec) {
|
|
@@ -1761,28 +1744,13 @@ class ManifestUpdater {
|
|
|
1761
1744
|
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
|
|
1762
1745
|
}
|
|
1763
1746
|
}
|
|
1764
|
-
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1747
|
+
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo) {
|
|
1765
1748
|
var _a, _b, _c, _d;
|
|
1766
1749
|
const warnings = [];
|
|
1767
1750
|
const functions = [];
|
|
1768
|
-
const
|
|
1751
|
+
const functionNamesMap = {};
|
|
1769
1752
|
const conversationStarters = [];
|
|
1770
1753
|
const paths = spec.paths;
|
|
1771
|
-
const pluginAuthObj = {
|
|
1772
|
-
type: "None",
|
|
1773
|
-
};
|
|
1774
|
-
if (authInfo) {
|
|
1775
|
-
if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
|
|
1776
|
-
pluginAuthObj.type = "OAuthPluginVault";
|
|
1777
|
-
}
|
|
1778
|
-
else if (Utils.isBearerTokenAuth(authInfo.authScheme)) {
|
|
1779
|
-
pluginAuthObj.type = "ApiKeyPluginVault";
|
|
1780
|
-
}
|
|
1781
|
-
if (pluginAuthObj.type !== "None") {
|
|
1782
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
|
|
1783
|
-
pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
1754
|
for (const pathUrl in paths) {
|
|
1787
1755
|
const pathItem = paths[pathUrl];
|
|
1788
1756
|
if (pathItem) {
|
|
@@ -1790,36 +1758,11 @@ class ManifestUpdater {
|
|
|
1790
1758
|
for (const method in operations) {
|
|
1791
1759
|
if (options.allowMethods.includes(method)) {
|
|
1792
1760
|
const operationItem = operations[method];
|
|
1793
|
-
const confirmationBodies = [];
|
|
1794
1761
|
if (operationItem) {
|
|
1795
1762
|
const operationId = operationItem.operationId;
|
|
1796
1763
|
const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1797
1764
|
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
1798
1765
|
const summary = operationItem.summary;
|
|
1799
|
-
const paramObject = operationItem.parameters;
|
|
1800
|
-
const requestBody = operationItem.requestBody;
|
|
1801
|
-
if (paramObject) {
|
|
1802
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
1803
|
-
const param = paramObject[i];
|
|
1804
|
-
const schema = param.schema;
|
|
1805
|
-
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1806
|
-
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1809
|
-
if (requestBody) {
|
|
1810
|
-
const requestJsonBody = requestBody.content["application/json"];
|
|
1811
|
-
const requestBodySchema = requestJsonBody.schema;
|
|
1812
|
-
if (Utils.isObjectSchema(requestBodySchema)) {
|
|
1813
|
-
for (const property in requestBodySchema.properties) {
|
|
1814
|
-
const schema = requestBodySchema.properties[property];
|
|
1815
|
-
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1816
|
-
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1819
|
-
else {
|
|
1820
|
-
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
|
|
1821
|
-
}
|
|
1822
|
-
}
|
|
1823
1766
|
let funcDescription = operationItem.description || operationItem.summary || "";
|
|
1824
1767
|
if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
|
|
1825
1768
|
warnings.push({
|
|
@@ -1853,19 +1796,66 @@ class ManifestUpdater {
|
|
|
1853
1796
|
}
|
|
1854
1797
|
}
|
|
1855
1798
|
if (options.allowConfirmation && method !== ConstantString.GetMethod) {
|
|
1856
|
-
|
|
1857
|
-
|
|
1799
|
+
const paramObject = operationItem.parameters;
|
|
1800
|
+
const requestBody = operationItem.requestBody;
|
|
1801
|
+
const confirmationBodies = [];
|
|
1802
|
+
if (paramObject) {
|
|
1803
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
1804
|
+
const param = paramObject[i];
|
|
1805
|
+
const schema = param.schema;
|
|
1806
|
+
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1807
|
+
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
if (requestBody) {
|
|
1811
|
+
const requestJsonBody = Utils.getJsonContentType(requestBody);
|
|
1812
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
1813
|
+
if (Utils.isObjectSchema(requestBodySchema)) {
|
|
1814
|
+
for (const property in requestBodySchema.properties) {
|
|
1815
|
+
const schema = requestBodySchema.properties[property];
|
|
1816
|
+
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1817
|
+
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
else {
|
|
1821
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
|
|
1822
|
+
}
|
|
1858
1823
|
}
|
|
1859
|
-
funcObj.capabilities.confirmation = {
|
|
1860
|
-
type: "AdaptiveCard",
|
|
1861
|
-
title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
|
|
1862
|
-
};
|
|
1863
1824
|
if (confirmationBodies.length > 0) {
|
|
1825
|
+
if (!funcObj.capabilities) {
|
|
1826
|
+
funcObj.capabilities = {};
|
|
1827
|
+
}
|
|
1828
|
+
funcObj.capabilities.confirmation = {
|
|
1829
|
+
type: "AdaptiveCard",
|
|
1830
|
+
title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
|
|
1831
|
+
};
|
|
1864
1832
|
funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
|
|
1865
1833
|
}
|
|
1866
1834
|
}
|
|
1867
1835
|
functions.push(funcObj);
|
|
1868
|
-
|
|
1836
|
+
const authInfo = authMap[operationId];
|
|
1837
|
+
let key = "None";
|
|
1838
|
+
let authName = "None";
|
|
1839
|
+
if (authInfo) {
|
|
1840
|
+
if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
|
|
1841
|
+
key = "OAuthPluginVault";
|
|
1842
|
+
authName = authInfo.name;
|
|
1843
|
+
}
|
|
1844
|
+
else if (Utils.isBearerTokenAuth(authInfo.authScheme) ||
|
|
1845
|
+
Utils.isAPIKeyAuthButNotInCookie(authInfo.authScheme)) {
|
|
1846
|
+
key = "ApiKeyPluginVault";
|
|
1847
|
+
authName = authInfo.name;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
if (functionNamesMap[key]) {
|
|
1851
|
+
functionNamesMap[key].functionNames.push(safeFunctionName);
|
|
1852
|
+
}
|
|
1853
|
+
else {
|
|
1854
|
+
functionNamesMap[key] = {
|
|
1855
|
+
functionNames: [safeFunctionName],
|
|
1856
|
+
authName: authName,
|
|
1857
|
+
};
|
|
1858
|
+
}
|
|
1869
1859
|
const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
|
|
1870
1860
|
if (conversationStarterStr) {
|
|
1871
1861
|
conversationStarters.push(conversationStarterStr);
|
|
@@ -1875,6 +1865,12 @@ class ManifestUpdater {
|
|
|
1875
1865
|
}
|
|
1876
1866
|
}
|
|
1877
1867
|
}
|
|
1868
|
+
if (Object.keys(functionNamesMap).length === 0) {
|
|
1869
|
+
functionNamesMap["None"] = {
|
|
1870
|
+
functionNames: [],
|
|
1871
|
+
authName: "None",
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1878
1874
|
let apiPlugin;
|
|
1879
1875
|
if (await fs.pathExists(apiPluginFilePath)) {
|
|
1880
1876
|
apiPlugin = await fs.readJSON(apiPluginFilePath);
|
|
@@ -1910,24 +1906,35 @@ class ManifestUpdater {
|
|
|
1910
1906
|
const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
|
|
1911
1907
|
apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
|
|
1912
1908
|
}
|
|
1913
|
-
const
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1909
|
+
for (const authType in functionNamesMap) {
|
|
1910
|
+
const pluginAuthObj = {
|
|
1911
|
+
type: authType,
|
|
1912
|
+
};
|
|
1913
|
+
const authName = functionNamesMap[authType].authName;
|
|
1914
|
+
if (pluginAuthObj.type !== "None") {
|
|
1915
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authName}_${ConstantString.RegistrationIdPostfix}`);
|
|
1916
|
+
pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
|
|
1917
|
+
}
|
|
1918
|
+
const functionNamesInfo = functionNamesMap[authType];
|
|
1919
|
+
const index = apiPlugin.runtimes.findIndex((runtime) => {
|
|
1920
|
+
var _a, _b;
|
|
1921
|
+
return runtime.spec.url === specRelativePath &&
|
|
1922
|
+
runtime.type === "OpenApi" &&
|
|
1923
|
+
((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === authType;
|
|
1927
1924
|
});
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1925
|
+
if (index === -1) {
|
|
1926
|
+
apiPlugin.runtimes.push({
|
|
1927
|
+
type: "OpenApi",
|
|
1928
|
+
auth: pluginAuthObj,
|
|
1929
|
+
spec: {
|
|
1930
|
+
url: specRelativePath,
|
|
1931
|
+
},
|
|
1932
|
+
run_for_functions: functionNamesInfo.functionNames,
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
else {
|
|
1936
|
+
apiPlugin.runtimes[index].run_for_functions = functionNamesInfo.functionNames;
|
|
1937
|
+
}
|
|
1931
1938
|
}
|
|
1932
1939
|
if (!apiPlugin.name_for_human) {
|
|
1933
1940
|
apiPlugin.name_for_human = appName;
|
|
@@ -1968,7 +1975,7 @@ class ManifestUpdater {
|
|
|
1968
1975
|
};
|
|
1969
1976
|
if (authInfo) {
|
|
1970
1977
|
const auth = authInfo.authScheme;
|
|
1971
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix
|
|
1978
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
1972
1979
|
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1973
1980
|
composeExtension.authorization = {
|
|
1974
1981
|
authType: "apiSecretServiceAuth",
|
|
@@ -2111,8 +2118,11 @@ class SpecParser {
|
|
|
2111
2118
|
await this.parser.validate(this.spec);
|
|
2112
2119
|
}
|
|
2113
2120
|
else {
|
|
2121
|
+
// The following code still hangs for Graph API, support will be added when SwaggerParser is updated.
|
|
2122
|
+
/*
|
|
2114
2123
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2115
2124
|
await this.parser.validate(clonedUnResolveSpec);
|
|
2125
|
+
*/
|
|
2116
2126
|
}
|
|
2117
2127
|
}
|
|
2118
2128
|
catch (e) {
|
|
@@ -2269,7 +2279,7 @@ class SpecParser {
|
|
|
2269
2279
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
2270
2280
|
}
|
|
2271
2281
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
|
|
2272
|
-
const newSpec =
|
|
2282
|
+
const newSpec = await this.deReferenceSpec(clonedUnResolveSpec);
|
|
2273
2283
|
return [newUnResolvedSpec, newSpec];
|
|
2274
2284
|
}
|
|
2275
2285
|
catch (err) {
|
|
@@ -2279,6 +2289,10 @@ class SpecParser {
|
|
|
2279
2289
|
throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
|
|
2280
2290
|
}
|
|
2281
2291
|
}
|
|
2292
|
+
async deReferenceSpec(spec) {
|
|
2293
|
+
const result = await this.parser.dereference(spec);
|
|
2294
|
+
return result;
|
|
2295
|
+
}
|
|
2282
2296
|
/**
|
|
2283
2297
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
2284
2298
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
@@ -2295,7 +2309,6 @@ class SpecParser {
|
|
|
2295
2309
|
const newSpecs = await this.getFilteredSpecs(filter, signal);
|
|
2296
2310
|
const newUnResolvedSpec = newSpecs[0];
|
|
2297
2311
|
const newSpec = newSpecs[1];
|
|
2298
|
-
const authInfo = Utils.getAuthInfo(newSpec);
|
|
2299
2312
|
const paths = newUnResolvedSpec.paths;
|
|
2300
2313
|
for (const pathUrl in paths) {
|
|
2301
2314
|
const operations = paths[pathUrl];
|
|
@@ -2303,15 +2316,22 @@ class SpecParser {
|
|
|
2303
2316
|
const operationItem = operations[method];
|
|
2304
2317
|
const operationId = operationItem.operationId;
|
|
2305
2318
|
const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
|
|
2306
|
-
if (
|
|
2307
|
-
|
|
2319
|
+
if (containsSpecialCharacters) {
|
|
2320
|
+
operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2321
|
+
result.warnings.push({
|
|
2322
|
+
type: WarningType.OperationIdContainsSpecialCharacters,
|
|
2323
|
+
content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
|
|
2324
|
+
data: operationId,
|
|
2325
|
+
});
|
|
2326
|
+
}
|
|
2327
|
+
const authArray = Utils.getAuthArray(operationItem.security, newSpec);
|
|
2328
|
+
if (Utils.isNotSupportedAuth(authArray)) {
|
|
2329
|
+
result.warnings.push({
|
|
2330
|
+
type: WarningType.UnsupportedAuthType,
|
|
2331
|
+
content: Utils.format(ConstantString.AuthTypeIsNotSupported, operationId),
|
|
2332
|
+
data: operationId,
|
|
2333
|
+
});
|
|
2308
2334
|
}
|
|
2309
|
-
operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2310
|
-
result.warnings.push({
|
|
2311
|
-
type: WarningType.OperationIdContainsSpecialCharacters,
|
|
2312
|
-
content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
|
|
2313
|
-
data: operationId,
|
|
2314
|
-
});
|
|
2315
2335
|
}
|
|
2316
2336
|
}
|
|
2317
2337
|
await this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
|
|
@@ -2324,7 +2344,8 @@ class SpecParser {
|
|
|
2324
2344
|
specPath: this.pathOrSpec,
|
|
2325
2345
|
}
|
|
2326
2346
|
: undefined;
|
|
2327
|
-
const
|
|
2347
|
+
const authMap = Utils.getAuthMap(newSpec);
|
|
2348
|
+
const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authMap, existingPluginManifestInfo);
|
|
2328
2349
|
result.warnings.push(...warnings);
|
|
2329
2350
|
await fs.outputJSON(manifestPath, updatedManifest, { spaces: 4 });
|
|
2330
2351
|
await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
|
|
@@ -2401,6 +2422,52 @@ class SpecParser {
|
|
|
2401
2422
|
}
|
|
2402
2423
|
return result;
|
|
2403
2424
|
}
|
|
2425
|
+
/**
|
|
2426
|
+
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
2427
|
+
* @param pluginFilePath A file path of the plugin manifest file to update.
|
|
2428
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
2429
|
+
*/
|
|
2430
|
+
async generateAdaptiveCardInPlugin(pluginFilePath, filter, signal) {
|
|
2431
|
+
if (!this.options.allowResponseSemantics) {
|
|
2432
|
+
return;
|
|
2433
|
+
}
|
|
2434
|
+
const newSpecs = await this.getFilteredSpecs(filter, signal);
|
|
2435
|
+
const newSpec = newSpecs[1];
|
|
2436
|
+
const apiPlugin = (await fs.readJSON(pluginFilePath));
|
|
2437
|
+
const paths = newSpec.paths;
|
|
2438
|
+
for (const pathUrl in paths) {
|
|
2439
|
+
const pathItem = paths[pathUrl];
|
|
2440
|
+
if (pathItem) {
|
|
2441
|
+
const operations = pathItem;
|
|
2442
|
+
for (const method in operations) {
|
|
2443
|
+
if (this.options.allowMethods.includes(method)) {
|
|
2444
|
+
const operationItem = operations[method];
|
|
2445
|
+
if (operationItem) {
|
|
2446
|
+
try {
|
|
2447
|
+
const operationId = operationItem.operationId;
|
|
2448
|
+
const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2449
|
+
if (apiPlugin.functions.findIndex((func) => func.name === safeFunctionName) === -1) {
|
|
2450
|
+
continue;
|
|
2451
|
+
}
|
|
2452
|
+
const { json } = Utils.getResponseJson(operationItem);
|
|
2453
|
+
if (json.schema) {
|
|
2454
|
+
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem, false, 5);
|
|
2455
|
+
const responseSemantic = wrapResponseSemantics(card, jsonPath);
|
|
2456
|
+
apiPlugin.functions.find((func) => func.name === safeFunctionName).capabilities = {
|
|
2457
|
+
response_semantics: responseSemantic,
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
catch (err) {
|
|
2462
|
+
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
|
|
2470
|
+
}
|
|
2404
2471
|
async loadSpec() {
|
|
2405
2472
|
if (!this.spec) {
|
|
2406
2473
|
const spec = (await this.parser.parse(this.pathOrSpec));
|
|
@@ -2412,7 +2479,7 @@ class SpecParser {
|
|
|
2412
2479
|
this.isSwaggerFile = true;
|
|
2413
2480
|
}
|
|
2414
2481
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2415
|
-
this.spec =
|
|
2482
|
+
this.spec = await this.deReferenceSpec(clonedUnResolveSpec);
|
|
2416
2483
|
}
|
|
2417
2484
|
}
|
|
2418
2485
|
getAPIs(spec) {
|