@microsoft/m365-spec-parser 0.2.4 → 0.2.5-alpha.038ce65fb.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 +299 -276
- 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 +302 -277
- 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 +2 -0
- package/dist/src/utils.d.ts +6 -3
- package/package.json +4 -4
package/dist/index.esm2017.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import fs from 'fs-extra';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { ManifestUtil } from '@microsoft/teams-manifest';
|
|
7
7
|
import { createHash } from 'crypto';
|
|
8
|
+
import { $RefParser } from '@apidevtools/json-schema-ref-parser';
|
|
8
9
|
|
|
9
10
|
// Copyright (c) Microsoft Corporation.
|
|
10
11
|
/**
|
|
@@ -38,11 +39,8 @@ var ErrorType;
|
|
|
38
39
|
ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
|
|
39
40
|
ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
|
|
40
41
|
ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
|
|
41
|
-
ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
|
|
42
42
|
ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
|
|
43
43
|
ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
|
|
44
|
-
ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
|
|
45
|
-
ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
|
|
46
44
|
ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
|
|
47
45
|
ErrorType["NoParameter"] = "no-parameter";
|
|
48
46
|
ErrorType["NoAPIInfo"] = "no-api-info";
|
|
@@ -62,6 +60,7 @@ var WarningType;
|
|
|
62
60
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
63
61
|
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
64
62
|
WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
|
|
63
|
+
WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
|
|
65
64
|
WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
66
65
|
WarningType["Unknown"] = "unknown";
|
|
67
66
|
})(WarningType || (WarningType = {}));
|
|
@@ -101,6 +100,7 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
|
|
|
101
100
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
102
101
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
103
102
|
ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
|
|
103
|
+
ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
|
|
104
104
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
105
105
|
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
106
|
ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
|
|
@@ -110,17 +110,12 @@ ConstantString.WrappedCardResponseLayout = "list";
|
|
|
110
110
|
ConstantString.GetMethod = "get";
|
|
111
111
|
ConstantString.PostMethod = "post";
|
|
112
112
|
ConstantString.AdaptiveCardVersion = "1.5";
|
|
113
|
-
ConstantString.AdaptiveCardSchema = "
|
|
113
|
+
ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
|
|
114
114
|
ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
115
115
|
ConstantString.TextBlockType = "TextBlock";
|
|
116
116
|
ConstantString.ImageType = "Image";
|
|
117
117
|
ConstantString.ContainerType = "Container";
|
|
118
|
-
ConstantString.RegistrationIdPostfix =
|
|
119
|
-
apiKey: "REGISTRATION_ID",
|
|
120
|
-
oauth2: "CONFIGURATION_ID",
|
|
121
|
-
http: "REGISTRATION_ID",
|
|
122
|
-
openIdConnect: "REGISTRATION_ID",
|
|
123
|
-
};
|
|
118
|
+
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
124
119
|
ConstantString.ResponseCodeFor20X = [
|
|
125
120
|
"200",
|
|
126
121
|
"201",
|
|
@@ -132,6 +127,7 @@ ConstantString.ResponseCodeFor20X = [
|
|
|
132
127
|
"207",
|
|
133
128
|
"208",
|
|
134
129
|
"226",
|
|
130
|
+
"2XX",
|
|
135
131
|
"default",
|
|
136
132
|
];
|
|
137
133
|
ConstantString.AllOperationMethods = [
|
|
@@ -197,17 +193,6 @@ class SpecParserError extends Error {
|
|
|
197
193
|
|
|
198
194
|
// Copyright (c) Microsoft Corporation.
|
|
199
195
|
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
196
|
static isObjectSchema(schema) {
|
|
212
197
|
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
213
198
|
}
|
|
@@ -220,11 +205,32 @@ class Utils {
|
|
|
220
205
|
static isAPIKeyAuth(authScheme) {
|
|
221
206
|
return authScheme.type === "apiKey";
|
|
222
207
|
}
|
|
208
|
+
static isAPIKeyAuthButNotInCookie(authScheme) {
|
|
209
|
+
return authScheme.type === "apiKey" && authScheme.in !== "cookie";
|
|
210
|
+
}
|
|
223
211
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
224
212
|
return !!(authScheme.type === "oauth2" &&
|
|
225
213
|
authScheme.flows &&
|
|
226
214
|
authScheme.flows.authorizationCode);
|
|
227
215
|
}
|
|
216
|
+
static isNotSupportedAuth(authSchemeArray) {
|
|
217
|
+
if (authSchemeArray.length === 0) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
for (const auths of authSchemeArray) {
|
|
224
|
+
if (auths.length === 1) {
|
|
225
|
+
if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
|
|
226
|
+
Utils.isBearerTokenAuth(auths[0].authScheme) ||
|
|
227
|
+
Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
228
234
|
static getAuthArray(securities, spec) {
|
|
229
235
|
var _a;
|
|
230
236
|
const result = [];
|
|
@@ -249,6 +255,20 @@ class Utils {
|
|
|
249
255
|
result.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
250
256
|
return result;
|
|
251
257
|
}
|
|
258
|
+
static getAuthMap(spec) {
|
|
259
|
+
const authMap = {};
|
|
260
|
+
for (const url in spec.paths) {
|
|
261
|
+
for (const method in spec.paths[url]) {
|
|
262
|
+
const operation = spec.paths[url][method];
|
|
263
|
+
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
264
|
+
if (authArray && authArray.length > 0) {
|
|
265
|
+
const currentAuth = authArray[0][0];
|
|
266
|
+
authMap[operation.operationId] = currentAuth;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return authMap;
|
|
271
|
+
}
|
|
252
272
|
static getAuthInfo(spec) {
|
|
253
273
|
let authInfo = undefined;
|
|
254
274
|
for (const url in spec.paths) {
|
|
@@ -277,27 +297,33 @@ class Utils {
|
|
|
277
297
|
let multipleMediaType = false;
|
|
278
298
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
279
299
|
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
|
-
}
|
|
300
|
+
if (!responseObject) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
|
|
304
|
+
if (!allowMultipleMediaType && multipleMediaType) {
|
|
305
|
+
json = {};
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const mediaObj = Utils.getJsonContentType(responseObject);
|
|
309
|
+
if (Object.keys(mediaObj).length > 0) {
|
|
310
|
+
json = mediaObj;
|
|
311
|
+
return { json, multipleMediaType };
|
|
297
312
|
}
|
|
298
313
|
}
|
|
299
314
|
return { json, multipleMediaType };
|
|
300
315
|
}
|
|
316
|
+
static getJsonContentType(responseObject) {
|
|
317
|
+
if (responseObject.content) {
|
|
318
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
319
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
320
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
321
|
+
return responseObject.content[contentType];
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return {};
|
|
326
|
+
}
|
|
301
327
|
static convertPathToCamelCase(path) {
|
|
302
328
|
const pathSegments = path.split(/[./{]/);
|
|
303
329
|
const camelCaseSegments = pathSegments.map((segment) => {
|
|
@@ -333,7 +359,7 @@ class Utils {
|
|
|
333
359
|
}
|
|
334
360
|
return newStr;
|
|
335
361
|
}
|
|
336
|
-
static checkServerUrl(servers) {
|
|
362
|
+
static checkServerUrl(servers, allowHttp = false) {
|
|
337
363
|
const errors = [];
|
|
338
364
|
let serverUrl;
|
|
339
365
|
try {
|
|
@@ -356,8 +382,7 @@ class Utils {
|
|
|
356
382
|
data: servers,
|
|
357
383
|
});
|
|
358
384
|
}
|
|
359
|
-
else if (protocol !== "https:") {
|
|
360
|
-
// Http server url is not supported
|
|
385
|
+
else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
|
|
361
386
|
const protocolString = protocol.slice(0, -1);
|
|
362
387
|
errors.push({
|
|
363
388
|
type: ErrorType.UrlProtocolNotSupported,
|
|
@@ -373,10 +398,11 @@ class Utils {
|
|
|
373
398
|
let hasTopLevelServers = false;
|
|
374
399
|
let hasPathLevelServers = false;
|
|
375
400
|
let hasOperationLevelServers = false;
|
|
401
|
+
const allowHttp = options.projectType === ProjectType.Copilot;
|
|
376
402
|
if (spec.servers && spec.servers.length >= 1) {
|
|
377
403
|
hasTopLevelServers = true;
|
|
378
404
|
// for multiple server, we only use the first url
|
|
379
|
-
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
405
|
+
const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
|
|
380
406
|
errors.push(...serverErrors);
|
|
381
407
|
}
|
|
382
408
|
const paths = spec.paths;
|
|
@@ -384,7 +410,7 @@ class Utils {
|
|
|
384
410
|
const methods = paths[path];
|
|
385
411
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
386
412
|
hasPathLevelServers = true;
|
|
387
|
-
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
413
|
+
const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
|
|
388
414
|
errors.push(...serverErrors);
|
|
389
415
|
}
|
|
390
416
|
for (const method in methods) {
|
|
@@ -392,7 +418,7 @@ class Utils {
|
|
|
392
418
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
393
419
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
394
420
|
hasOperationLevelServers = true;
|
|
395
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
421
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
|
|
396
422
|
errors.push(...serverErrors);
|
|
397
423
|
}
|
|
398
424
|
}
|
|
@@ -681,22 +707,6 @@ class Validator {
|
|
|
681
707
|
}
|
|
682
708
|
return result;
|
|
683
709
|
}
|
|
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
710
|
validateServer(method, path) {
|
|
701
711
|
const result = { isValid: true, reason: [] };
|
|
702
712
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -705,8 +715,8 @@ class Validator {
|
|
|
705
715
|
result.reason.push(ErrorType.NoServerInformation);
|
|
706
716
|
}
|
|
707
717
|
else {
|
|
708
|
-
|
|
709
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
718
|
+
const allowHttp = this.projectType === ProjectType.Copilot;
|
|
719
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
|
|
710
720
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
711
721
|
}
|
|
712
722
|
return result;
|
|
@@ -729,6 +739,9 @@ class Validator {
|
|
|
729
739
|
reason: [ErrorType.MultipleAuthNotSupported],
|
|
730
740
|
};
|
|
731
741
|
}
|
|
742
|
+
if (this.projectType === ProjectType.Copilot) {
|
|
743
|
+
return { isValid: true, reason: [] };
|
|
744
|
+
}
|
|
732
745
|
for (const auths of authSchemeArray) {
|
|
733
746
|
if (auths.length === 1) {
|
|
734
747
|
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
@@ -741,114 +754,6 @@ class Validator {
|
|
|
741
754
|
}
|
|
742
755
|
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
743
756
|
}
|
|
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
757
|
}
|
|
853
758
|
|
|
854
759
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -858,7 +763,6 @@ class CopilotValidator extends Validator {
|
|
|
858
763
|
this.projectType = ProjectType.Copilot;
|
|
859
764
|
this.options = options;
|
|
860
765
|
this.spec = spec;
|
|
861
|
-
this.checkCircularReference();
|
|
862
766
|
}
|
|
863
767
|
validateSpec() {
|
|
864
768
|
const result = { errors: [], warnings: [] };
|
|
@@ -884,10 +788,6 @@ class CopilotValidator extends Validator {
|
|
|
884
788
|
if (!methodAndPathResult.isValid) {
|
|
885
789
|
return methodAndPathResult;
|
|
886
790
|
}
|
|
887
|
-
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
888
|
-
if (!circularReferenceResult.isValid) {
|
|
889
|
-
return circularReferenceResult;
|
|
890
|
-
}
|
|
891
791
|
const operationObject = this.spec.paths[path][method];
|
|
892
792
|
// validate auth
|
|
893
793
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -899,24 +799,6 @@ class CopilotValidator extends Validator {
|
|
|
899
799
|
// validate server
|
|
900
800
|
const validateServerResult = this.validateServer(method, path);
|
|
901
801
|
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
802
|
if (result.reason.length > 0) {
|
|
921
803
|
result.isValid = false;
|
|
922
804
|
}
|
|
@@ -1008,6 +890,108 @@ class SMEValidator extends Validator {
|
|
|
1008
890
|
}
|
|
1009
891
|
return result;
|
|
1010
892
|
}
|
|
893
|
+
validateResponse(method, path) {
|
|
894
|
+
const result = { isValid: true, reason: [] };
|
|
895
|
+
const operationObject = this.spec.paths[path][method];
|
|
896
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
897
|
+
// only support response body only contains “application/json” content type
|
|
898
|
+
if (multipleMediaType) {
|
|
899
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
900
|
+
}
|
|
901
|
+
else if (Object.keys(json).length === 0) {
|
|
902
|
+
// response body should not be empty
|
|
903
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
904
|
+
}
|
|
905
|
+
return result;
|
|
906
|
+
}
|
|
907
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
908
|
+
var _a;
|
|
909
|
+
const paramResult = {
|
|
910
|
+
requiredNum: 0,
|
|
911
|
+
optionalNum: 0,
|
|
912
|
+
isValid: true,
|
|
913
|
+
reason: [],
|
|
914
|
+
};
|
|
915
|
+
if (Object.keys(schema).length === 0) {
|
|
916
|
+
return paramResult;
|
|
917
|
+
}
|
|
918
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
919
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
920
|
+
if (schema.type === "string" ||
|
|
921
|
+
schema.type === "integer" ||
|
|
922
|
+
schema.type === "boolean" ||
|
|
923
|
+
schema.type === "number") {
|
|
924
|
+
if (isRequiredWithoutDefault) {
|
|
925
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
932
|
+
const { properties } = schema;
|
|
933
|
+
for (const property in properties) {
|
|
934
|
+
let isRequired = false;
|
|
935
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
936
|
+
isRequired = true;
|
|
937
|
+
}
|
|
938
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
939
|
+
paramResult.requiredNum += result.requiredNum;
|
|
940
|
+
paramResult.optionalNum += result.optionalNum;
|
|
941
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
942
|
+
paramResult.reason.push(...result.reason);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
else {
|
|
946
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
947
|
+
paramResult.isValid = false;
|
|
948
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
return paramResult;
|
|
952
|
+
}
|
|
953
|
+
checkParamSchema(paramObject) {
|
|
954
|
+
const paramResult = {
|
|
955
|
+
requiredNum: 0,
|
|
956
|
+
optionalNum: 0,
|
|
957
|
+
isValid: true,
|
|
958
|
+
reason: [],
|
|
959
|
+
};
|
|
960
|
+
if (!paramObject) {
|
|
961
|
+
return paramResult;
|
|
962
|
+
}
|
|
963
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
964
|
+
const param = paramObject[i];
|
|
965
|
+
const schema = param.schema;
|
|
966
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
967
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
968
|
+
if (isRequiredWithoutDefault) {
|
|
969
|
+
paramResult.isValid = false;
|
|
970
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
971
|
+
}
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
if (schema.type !== "boolean" &&
|
|
975
|
+
schema.type !== "string" &&
|
|
976
|
+
schema.type !== "number" &&
|
|
977
|
+
schema.type !== "integer") {
|
|
978
|
+
if (isRequiredWithoutDefault) {
|
|
979
|
+
paramResult.isValid = false;
|
|
980
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
981
|
+
}
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
if (param.in === "query" || param.in === "path") {
|
|
985
|
+
if (isRequiredWithoutDefault) {
|
|
986
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
987
|
+
}
|
|
988
|
+
else {
|
|
989
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
return paramResult;
|
|
994
|
+
}
|
|
1011
995
|
validateParamCount(postBodyResult, paramResult) {
|
|
1012
996
|
const result = { isValid: true, reason: [] };
|
|
1013
997
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
@@ -1709,7 +1693,7 @@ function inferProperties(card) {
|
|
|
1709
1693
|
|
|
1710
1694
|
// Copyright (c) Microsoft Corporation.
|
|
1711
1695
|
class ManifestUpdater {
|
|
1712
|
-
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options,
|
|
1696
|
+
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authMap, existingPluginManifestInfo) {
|
|
1713
1697
|
const manifest = await fs.readJSON(manifestPath);
|
|
1714
1698
|
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
1715
1699
|
const useCopilotExtensionsInSchema = await ManifestUtil.useCopilotExtensionsInSchema(manifest);
|
|
@@ -1739,7 +1723,7 @@ class ManifestUpdater {
|
|
|
1739
1723
|
}
|
|
1740
1724
|
const appName = this.removeEnvs(manifest.name.short);
|
|
1741
1725
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
1742
|
-
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1726
|
+
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo);
|
|
1743
1727
|
return [manifest, apiPlugin, warnings];
|
|
1744
1728
|
}
|
|
1745
1729
|
static updateManifestDescription(manifest, spec) {
|
|
@@ -1761,28 +1745,13 @@ class ManifestUpdater {
|
|
|
1761
1745
|
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
|
|
1762
1746
|
}
|
|
1763
1747
|
}
|
|
1764
|
-
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1748
|
+
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo) {
|
|
1765
1749
|
var _a, _b, _c, _d;
|
|
1766
1750
|
const warnings = [];
|
|
1767
1751
|
const functions = [];
|
|
1768
|
-
const
|
|
1752
|
+
const functionNamesMap = {};
|
|
1769
1753
|
const conversationStarters = [];
|
|
1770
1754
|
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
1755
|
for (const pathUrl in paths) {
|
|
1787
1756
|
const pathItem = paths[pathUrl];
|
|
1788
1757
|
if (pathItem) {
|
|
@@ -1790,36 +1759,11 @@ class ManifestUpdater {
|
|
|
1790
1759
|
for (const method in operations) {
|
|
1791
1760
|
if (options.allowMethods.includes(method)) {
|
|
1792
1761
|
const operationItem = operations[method];
|
|
1793
|
-
const confirmationBodies = [];
|
|
1794
1762
|
if (operationItem) {
|
|
1795
1763
|
const operationId = operationItem.operationId;
|
|
1796
1764
|
const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1797
1765
|
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
1798
1766
|
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
1767
|
let funcDescription = operationItem.description || operationItem.summary || "";
|
|
1824
1768
|
if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
|
|
1825
1769
|
warnings.push({
|
|
@@ -1853,19 +1797,66 @@ class ManifestUpdater {
|
|
|
1853
1797
|
}
|
|
1854
1798
|
}
|
|
1855
1799
|
if (options.allowConfirmation && method !== ConstantString.GetMethod) {
|
|
1856
|
-
|
|
1857
|
-
|
|
1800
|
+
const paramObject = operationItem.parameters;
|
|
1801
|
+
const requestBody = operationItem.requestBody;
|
|
1802
|
+
const confirmationBodies = [];
|
|
1803
|
+
if (paramObject) {
|
|
1804
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
1805
|
+
const param = paramObject[i];
|
|
1806
|
+
const schema = param.schema;
|
|
1807
|
+
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1808
|
+
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
if (requestBody) {
|
|
1812
|
+
const requestJsonBody = Utils.getJsonContentType(requestBody);
|
|
1813
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
1814
|
+
if (Utils.isObjectSchema(requestBodySchema)) {
|
|
1815
|
+
for (const property in requestBodySchema.properties) {
|
|
1816
|
+
const schema = requestBodySchema.properties[property];
|
|
1817
|
+
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1818
|
+
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
else {
|
|
1822
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
|
|
1823
|
+
}
|
|
1858
1824
|
}
|
|
1859
|
-
funcObj.capabilities.confirmation = {
|
|
1860
|
-
type: "AdaptiveCard",
|
|
1861
|
-
title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
|
|
1862
|
-
};
|
|
1863
1825
|
if (confirmationBodies.length > 0) {
|
|
1826
|
+
if (!funcObj.capabilities) {
|
|
1827
|
+
funcObj.capabilities = {};
|
|
1828
|
+
}
|
|
1829
|
+
funcObj.capabilities.confirmation = {
|
|
1830
|
+
type: "AdaptiveCard",
|
|
1831
|
+
title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
|
|
1832
|
+
};
|
|
1864
1833
|
funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
|
|
1865
1834
|
}
|
|
1866
1835
|
}
|
|
1867
1836
|
functions.push(funcObj);
|
|
1868
|
-
|
|
1837
|
+
const authInfo = authMap[operationId];
|
|
1838
|
+
let key = "None";
|
|
1839
|
+
let authName = "None";
|
|
1840
|
+
if (authInfo) {
|
|
1841
|
+
if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
|
|
1842
|
+
key = "OAuthPluginVault";
|
|
1843
|
+
authName = authInfo.name;
|
|
1844
|
+
}
|
|
1845
|
+
else if (Utils.isBearerTokenAuth(authInfo.authScheme) ||
|
|
1846
|
+
Utils.isAPIKeyAuthButNotInCookie(authInfo.authScheme)) {
|
|
1847
|
+
key = "ApiKeyPluginVault";
|
|
1848
|
+
authName = authInfo.name;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
if (functionNamesMap[key]) {
|
|
1852
|
+
functionNamesMap[key].functionNames.push(safeFunctionName);
|
|
1853
|
+
}
|
|
1854
|
+
else {
|
|
1855
|
+
functionNamesMap[key] = {
|
|
1856
|
+
functionNames: [safeFunctionName],
|
|
1857
|
+
authName: authName,
|
|
1858
|
+
};
|
|
1859
|
+
}
|
|
1869
1860
|
const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
|
|
1870
1861
|
if (conversationStarterStr) {
|
|
1871
1862
|
conversationStarters.push(conversationStarterStr);
|
|
@@ -1875,6 +1866,12 @@ class ManifestUpdater {
|
|
|
1875
1866
|
}
|
|
1876
1867
|
}
|
|
1877
1868
|
}
|
|
1869
|
+
if (Object.keys(functionNamesMap).length === 0) {
|
|
1870
|
+
functionNamesMap["None"] = {
|
|
1871
|
+
functionNames: [],
|
|
1872
|
+
authName: "None",
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1878
1875
|
let apiPlugin;
|
|
1879
1876
|
if (await fs.pathExists(apiPluginFilePath)) {
|
|
1880
1877
|
apiPlugin = await fs.readJSON(apiPluginFilePath);
|
|
@@ -1910,24 +1907,35 @@ class ManifestUpdater {
|
|
|
1910
1907
|
const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
|
|
1911
1908
|
apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
|
|
1912
1909
|
}
|
|
1913
|
-
const
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1910
|
+
for (const authType in functionNamesMap) {
|
|
1911
|
+
const pluginAuthObj = {
|
|
1912
|
+
type: authType,
|
|
1913
|
+
};
|
|
1914
|
+
const authName = functionNamesMap[authType].authName;
|
|
1915
|
+
if (pluginAuthObj.type !== "None") {
|
|
1916
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authName}_${ConstantString.RegistrationIdPostfix}`);
|
|
1917
|
+
pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
|
|
1918
|
+
}
|
|
1919
|
+
const functionNamesInfo = functionNamesMap[authType];
|
|
1920
|
+
const index = apiPlugin.runtimes.findIndex((runtime) => {
|
|
1921
|
+
var _a, _b;
|
|
1922
|
+
return runtime.spec.url === specRelativePath &&
|
|
1923
|
+
runtime.type === "OpenApi" &&
|
|
1924
|
+
((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === authType;
|
|
1927
1925
|
});
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1926
|
+
if (index === -1) {
|
|
1927
|
+
apiPlugin.runtimes.push({
|
|
1928
|
+
type: "OpenApi",
|
|
1929
|
+
auth: pluginAuthObj,
|
|
1930
|
+
spec: {
|
|
1931
|
+
url: specRelativePath,
|
|
1932
|
+
},
|
|
1933
|
+
run_for_functions: functionNamesInfo.functionNames,
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
else {
|
|
1937
|
+
apiPlugin.runtimes[index].run_for_functions = functionNamesInfo.functionNames;
|
|
1938
|
+
}
|
|
1931
1939
|
}
|
|
1932
1940
|
if (!apiPlugin.name_for_human) {
|
|
1933
1941
|
apiPlugin.name_for_human = appName;
|
|
@@ -1968,7 +1976,7 @@ class ManifestUpdater {
|
|
|
1968
1976
|
};
|
|
1969
1977
|
if (authInfo) {
|
|
1970
1978
|
const auth = authInfo.authScheme;
|
|
1971
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix
|
|
1979
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
1972
1980
|
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1973
1981
|
composeExtension.authorization = {
|
|
1974
1982
|
authType: "apiSecretServiceAuth",
|
|
@@ -2095,6 +2103,7 @@ class SpecParser {
|
|
|
2095
2103
|
};
|
|
2096
2104
|
this.pathOrSpec = pathOrDoc;
|
|
2097
2105
|
this.parser = new SwaggerParser();
|
|
2106
|
+
this.refParser = new $RefParser();
|
|
2098
2107
|
this.options = Object.assign(Object.assign({}, this.defaultOptions), (options !== null && options !== void 0 ? options : {}));
|
|
2099
2108
|
}
|
|
2100
2109
|
/**
|
|
@@ -2107,12 +2116,15 @@ class SpecParser {
|
|
|
2107
2116
|
let hash = "";
|
|
2108
2117
|
try {
|
|
2109
2118
|
await this.loadSpec();
|
|
2110
|
-
if (!this.
|
|
2119
|
+
if (!this.refParser.$refs.circular) {
|
|
2111
2120
|
await this.parser.validate(this.spec);
|
|
2112
2121
|
}
|
|
2113
2122
|
else {
|
|
2123
|
+
// The following code hangs for Graph API, support will be added when SwaggerParser is updated.
|
|
2124
|
+
/*
|
|
2114
2125
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2115
2126
|
await this.parser.validate(clonedUnResolveSpec);
|
|
2127
|
+
*/
|
|
2116
2128
|
}
|
|
2117
2129
|
}
|
|
2118
2130
|
catch (e) {
|
|
@@ -2140,7 +2152,7 @@ class SpecParser {
|
|
|
2140
2152
|
};
|
|
2141
2153
|
}
|
|
2142
2154
|
// Remote reference not supported
|
|
2143
|
-
const refPaths = this.
|
|
2155
|
+
const refPaths = this.refParser.$refs.paths();
|
|
2144
2156
|
// refPaths [0] is the current spec file path
|
|
2145
2157
|
if (refPaths.length > 1) {
|
|
2146
2158
|
errors.push({
|
|
@@ -2269,7 +2281,7 @@ class SpecParser {
|
|
|
2269
2281
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
2270
2282
|
}
|
|
2271
2283
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
|
|
2272
|
-
const newSpec =
|
|
2284
|
+
const newSpec = await this.deReferenceSpec(clonedUnResolveSpec);
|
|
2273
2285
|
return [newUnResolvedSpec, newSpec];
|
|
2274
2286
|
}
|
|
2275
2287
|
catch (err) {
|
|
@@ -2279,6 +2291,10 @@ class SpecParser {
|
|
|
2279
2291
|
throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
|
|
2280
2292
|
}
|
|
2281
2293
|
}
|
|
2294
|
+
async deReferenceSpec(spec) {
|
|
2295
|
+
const result = await this.refParser.dereference(spec);
|
|
2296
|
+
return result;
|
|
2297
|
+
}
|
|
2282
2298
|
/**
|
|
2283
2299
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
2284
2300
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
@@ -2295,7 +2311,6 @@ class SpecParser {
|
|
|
2295
2311
|
const newSpecs = await this.getFilteredSpecs(filter, signal);
|
|
2296
2312
|
const newUnResolvedSpec = newSpecs[0];
|
|
2297
2313
|
const newSpec = newSpecs[1];
|
|
2298
|
-
const authInfo = Utils.getAuthInfo(newSpec);
|
|
2299
2314
|
const paths = newUnResolvedSpec.paths;
|
|
2300
2315
|
for (const pathUrl in paths) {
|
|
2301
2316
|
const operations = paths[pathUrl];
|
|
@@ -2303,15 +2318,22 @@ class SpecParser {
|
|
|
2303
2318
|
const operationItem = operations[method];
|
|
2304
2319
|
const operationId = operationItem.operationId;
|
|
2305
2320
|
const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
|
|
2306
|
-
if (
|
|
2307
|
-
|
|
2321
|
+
if (containsSpecialCharacters) {
|
|
2322
|
+
operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2323
|
+
result.warnings.push({
|
|
2324
|
+
type: WarningType.OperationIdContainsSpecialCharacters,
|
|
2325
|
+
content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
|
|
2326
|
+
data: operationId,
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
2329
|
+
const authArray = Utils.getAuthArray(operationItem.security, newSpec);
|
|
2330
|
+
if (Utils.isNotSupportedAuth(authArray)) {
|
|
2331
|
+
result.warnings.push({
|
|
2332
|
+
type: WarningType.UnsupportedAuthType,
|
|
2333
|
+
content: Utils.format(ConstantString.AuthTypeIsNotSupported, operationId),
|
|
2334
|
+
data: operationId,
|
|
2335
|
+
});
|
|
2308
2336
|
}
|
|
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
2337
|
}
|
|
2316
2338
|
}
|
|
2317
2339
|
await this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
|
|
@@ -2324,7 +2346,8 @@ class SpecParser {
|
|
|
2324
2346
|
specPath: this.pathOrSpec,
|
|
2325
2347
|
}
|
|
2326
2348
|
: undefined;
|
|
2327
|
-
const
|
|
2349
|
+
const authMap = Utils.getAuthMap(newSpec);
|
|
2350
|
+
const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authMap, existingPluginManifestInfo);
|
|
2328
2351
|
result.warnings.push(...warnings);
|
|
2329
2352
|
await fs.outputJSON(manifestPath, updatedManifest, { spaces: 4 });
|
|
2330
2353
|
await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
|
|
@@ -2412,7 +2435,7 @@ class SpecParser {
|
|
|
2412
2435
|
this.isSwaggerFile = true;
|
|
2413
2436
|
}
|
|
2414
2437
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2415
|
-
this.spec =
|
|
2438
|
+
this.spec = await this.deReferenceSpec(clonedUnResolveSpec);
|
|
2416
2439
|
}
|
|
2417
2440
|
}
|
|
2418
2441
|
getAPIs(spec) {
|