@microsoft/m365-spec-parser 0.2.4-rc.0 → 0.2.4-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm2017.js +193 -176
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +276 -299
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +193 -176
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +277 -302
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +4 -3
- package/dist/src/interfaces.d.ts +3 -10
- package/dist/src/manifestUpdater.d.ts +3 -3
- package/dist/src/specParser.d.ts +0 -2
- package/dist/src/utils.d.ts +3 -6
- package/package.json +4 -4
package/dist/index.esm2017.mjs
CHANGED
|
@@ -5,7 +5,6 @@ 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';
|
|
9
8
|
|
|
10
9
|
// Copyright (c) Microsoft Corporation.
|
|
11
10
|
/**
|
|
@@ -39,8 +38,11 @@ var ErrorType;
|
|
|
39
38
|
ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
|
|
40
39
|
ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
|
|
41
40
|
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";
|
|
44
46
|
ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
|
|
45
47
|
ErrorType["NoParameter"] = "no-parameter";
|
|
46
48
|
ErrorType["NoAPIInfo"] = "no-api-info";
|
|
@@ -60,7 +62,6 @@ var WarningType;
|
|
|
60
62
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
61
63
|
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
62
64
|
WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
|
|
63
|
-
WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
|
|
64
65
|
WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
65
66
|
WarningType["Unknown"] = "unknown";
|
|
66
67
|
})(WarningType || (WarningType = {}));
|
|
@@ -100,7 +101,6 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
|
|
|
100
101
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
101
102
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
102
103
|
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,12 +110,17 @@ 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 = "http://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 =
|
|
118
|
+
ConstantString.RegistrationIdPostfix = {
|
|
119
|
+
apiKey: "REGISTRATION_ID",
|
|
120
|
+
oauth2: "CONFIGURATION_ID",
|
|
121
|
+
http: "REGISTRATION_ID",
|
|
122
|
+
openIdConnect: "REGISTRATION_ID",
|
|
123
|
+
};
|
|
119
124
|
ConstantString.ResponseCodeFor20X = [
|
|
120
125
|
"200",
|
|
121
126
|
"201",
|
|
@@ -127,7 +132,6 @@ ConstantString.ResponseCodeFor20X = [
|
|
|
127
132
|
"207",
|
|
128
133
|
"208",
|
|
129
134
|
"226",
|
|
130
|
-
"2XX",
|
|
131
135
|
"default",
|
|
132
136
|
];
|
|
133
137
|
ConstantString.AllOperationMethods = [
|
|
@@ -193,6 +197,17 @@ class SpecParserError extends Error {
|
|
|
193
197
|
|
|
194
198
|
// Copyright (c) Microsoft Corporation.
|
|
195
199
|
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
|
+
}
|
|
196
211
|
static isObjectSchema(schema) {
|
|
197
212
|
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
198
213
|
}
|
|
@@ -205,32 +220,11 @@ class Utils {
|
|
|
205
220
|
static isAPIKeyAuth(authScheme) {
|
|
206
221
|
return authScheme.type === "apiKey";
|
|
207
222
|
}
|
|
208
|
-
static isAPIKeyAuthButNotInCookie(authScheme) {
|
|
209
|
-
return authScheme.type === "apiKey" && authScheme.in !== "cookie";
|
|
210
|
-
}
|
|
211
223
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
212
224
|
return !!(authScheme.type === "oauth2" &&
|
|
213
225
|
authScheme.flows &&
|
|
214
226
|
authScheme.flows.authorizationCode);
|
|
215
227
|
}
|
|
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
|
-
}
|
|
234
228
|
static getAuthArray(securities, spec) {
|
|
235
229
|
var _a;
|
|
236
230
|
const result = [];
|
|
@@ -255,20 +249,6 @@ class Utils {
|
|
|
255
249
|
result.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
256
250
|
return result;
|
|
257
251
|
}
|
|
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
|
-
}
|
|
272
252
|
static getAuthInfo(spec) {
|
|
273
253
|
let authInfo = undefined;
|
|
274
254
|
for (const url in spec.paths) {
|
|
@@ -297,32 +277,26 @@ class Utils {
|
|
|
297
277
|
let multipleMediaType = false;
|
|
298
278
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
299
279
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
300
|
-
if (
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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];
|
|
280
|
+
if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
|
|
281
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
282
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
283
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
284
|
+
multipleMediaType = false;
|
|
285
|
+
json = responseObject.content[contentType];
|
|
286
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
287
|
+
multipleMediaType = true;
|
|
288
|
+
if (!allowMultipleMediaType) {
|
|
289
|
+
json = {};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
return { json, multipleMediaType };
|
|
294
|
+
}
|
|
295
|
+
}
|
|
322
296
|
}
|
|
323
297
|
}
|
|
324
298
|
}
|
|
325
|
-
return {};
|
|
299
|
+
return { json, multipleMediaType };
|
|
326
300
|
}
|
|
327
301
|
static convertPathToCamelCase(path) {
|
|
328
302
|
const pathSegments = path.split(/[./{]/);
|
|
@@ -359,7 +333,7 @@ class Utils {
|
|
|
359
333
|
}
|
|
360
334
|
return newStr;
|
|
361
335
|
}
|
|
362
|
-
static checkServerUrl(servers
|
|
336
|
+
static checkServerUrl(servers) {
|
|
363
337
|
const errors = [];
|
|
364
338
|
let serverUrl;
|
|
365
339
|
try {
|
|
@@ -382,7 +356,8 @@ class Utils {
|
|
|
382
356
|
data: servers,
|
|
383
357
|
});
|
|
384
358
|
}
|
|
385
|
-
else if (protocol !== "https:"
|
|
359
|
+
else if (protocol !== "https:") {
|
|
360
|
+
// Http server url is not supported
|
|
386
361
|
const protocolString = protocol.slice(0, -1);
|
|
387
362
|
errors.push({
|
|
388
363
|
type: ErrorType.UrlProtocolNotSupported,
|
|
@@ -398,11 +373,10 @@ class Utils {
|
|
|
398
373
|
let hasTopLevelServers = false;
|
|
399
374
|
let hasPathLevelServers = false;
|
|
400
375
|
let hasOperationLevelServers = false;
|
|
401
|
-
const allowHttp = options.projectType === ProjectType.Copilot;
|
|
402
376
|
if (spec.servers && spec.servers.length >= 1) {
|
|
403
377
|
hasTopLevelServers = true;
|
|
404
378
|
// for multiple server, we only use the first url
|
|
405
|
-
const serverErrors = Utils.checkServerUrl(spec.servers
|
|
379
|
+
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
406
380
|
errors.push(...serverErrors);
|
|
407
381
|
}
|
|
408
382
|
const paths = spec.paths;
|
|
@@ -410,7 +384,7 @@ class Utils {
|
|
|
410
384
|
const methods = paths[path];
|
|
411
385
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
412
386
|
hasPathLevelServers = true;
|
|
413
|
-
const serverErrors = Utils.checkServerUrl(methods.servers
|
|
387
|
+
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
414
388
|
errors.push(...serverErrors);
|
|
415
389
|
}
|
|
416
390
|
for (const method in methods) {
|
|
@@ -418,7 +392,7 @@ class Utils {
|
|
|
418
392
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
419
393
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
420
394
|
hasOperationLevelServers = true;
|
|
421
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers
|
|
395
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
422
396
|
errors.push(...serverErrors);
|
|
423
397
|
}
|
|
424
398
|
}
|
|
@@ -707,6 +681,22 @@ class Validator {
|
|
|
707
681
|
}
|
|
708
682
|
return result;
|
|
709
683
|
}
|
|
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
|
+
}
|
|
710
700
|
validateServer(method, path) {
|
|
711
701
|
const result = { isValid: true, reason: [] };
|
|
712
702
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -715,8 +705,8 @@ class Validator {
|
|
|
715
705
|
result.reason.push(ErrorType.NoServerInformation);
|
|
716
706
|
}
|
|
717
707
|
else {
|
|
718
|
-
|
|
719
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]
|
|
708
|
+
// server url should be absolute url with https protocol
|
|
709
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
720
710
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
721
711
|
}
|
|
722
712
|
return result;
|
|
@@ -739,9 +729,6 @@ class Validator {
|
|
|
739
729
|
reason: [ErrorType.MultipleAuthNotSupported],
|
|
740
730
|
};
|
|
741
731
|
}
|
|
742
|
-
if (this.projectType === ProjectType.Copilot) {
|
|
743
|
-
return { isValid: true, reason: [] };
|
|
744
|
-
}
|
|
745
732
|
for (const auths of authSchemeArray) {
|
|
746
733
|
if (auths.length === 1) {
|
|
747
734
|
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
@@ -754,6 +741,114 @@ class Validator {
|
|
|
754
741
|
}
|
|
755
742
|
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
756
743
|
}
|
|
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
|
+
}
|
|
757
852
|
}
|
|
758
853
|
|
|
759
854
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -763,6 +858,7 @@ class CopilotValidator extends Validator {
|
|
|
763
858
|
this.projectType = ProjectType.Copilot;
|
|
764
859
|
this.options = options;
|
|
765
860
|
this.spec = spec;
|
|
861
|
+
this.checkCircularReference();
|
|
766
862
|
}
|
|
767
863
|
validateSpec() {
|
|
768
864
|
const result = { errors: [], warnings: [] };
|
|
@@ -788,6 +884,10 @@ class CopilotValidator extends Validator {
|
|
|
788
884
|
if (!methodAndPathResult.isValid) {
|
|
789
885
|
return methodAndPathResult;
|
|
790
886
|
}
|
|
887
|
+
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
888
|
+
if (!circularReferenceResult.isValid) {
|
|
889
|
+
return circularReferenceResult;
|
|
890
|
+
}
|
|
791
891
|
const operationObject = this.spec.paths[path][method];
|
|
792
892
|
// validate auth
|
|
793
893
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -799,6 +899,24 @@ class CopilotValidator extends Validator {
|
|
|
799
899
|
// validate server
|
|
800
900
|
const validateServerResult = this.validateServer(method, path);
|
|
801
901
|
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);
|
|
802
920
|
if (result.reason.length > 0) {
|
|
803
921
|
result.isValid = false;
|
|
804
922
|
}
|
|
@@ -890,108 +1008,6 @@ class SMEValidator extends Validator {
|
|
|
890
1008
|
}
|
|
891
1009
|
return result;
|
|
892
1010
|
}
|
|
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
|
-
}
|
|
995
1011
|
validateParamCount(postBodyResult, paramResult) {
|
|
996
1012
|
const result = { isValid: true, reason: [] };
|
|
997
1013
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
@@ -1693,7 +1709,7 @@ function inferProperties(card) {
|
|
|
1693
1709
|
|
|
1694
1710
|
// Copyright (c) Microsoft Corporation.
|
|
1695
1711
|
class ManifestUpdater {
|
|
1696
|
-
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options,
|
|
1712
|
+
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authInfo, existingPluginManifestInfo) {
|
|
1697
1713
|
const manifest = await fs.readJSON(manifestPath);
|
|
1698
1714
|
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
1699
1715
|
const useCopilotExtensionsInSchema = await ManifestUtil.useCopilotExtensionsInSchema(manifest);
|
|
@@ -1723,7 +1739,7 @@ class ManifestUpdater {
|
|
|
1723
1739
|
}
|
|
1724
1740
|
const appName = this.removeEnvs(manifest.name.short);
|
|
1725
1741
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
1726
|
-
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1742
|
+
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo);
|
|
1727
1743
|
return [manifest, apiPlugin, warnings];
|
|
1728
1744
|
}
|
|
1729
1745
|
static updateManifestDescription(manifest, spec) {
|
|
@@ -1745,13 +1761,28 @@ class ManifestUpdater {
|
|
|
1745
1761
|
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
|
|
1746
1762
|
}
|
|
1747
1763
|
}
|
|
1748
|
-
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1764
|
+
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo) {
|
|
1749
1765
|
var _a, _b, _c, _d;
|
|
1750
1766
|
const warnings = [];
|
|
1751
1767
|
const functions = [];
|
|
1752
|
-
const
|
|
1768
|
+
const functionNames = [];
|
|
1753
1769
|
const conversationStarters = [];
|
|
1754
1770
|
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
|
+
}
|
|
1755
1786
|
for (const pathUrl in paths) {
|
|
1756
1787
|
const pathItem = paths[pathUrl];
|
|
1757
1788
|
if (pathItem) {
|
|
@@ -1759,11 +1790,36 @@ class ManifestUpdater {
|
|
|
1759
1790
|
for (const method in operations) {
|
|
1760
1791
|
if (options.allowMethods.includes(method)) {
|
|
1761
1792
|
const operationItem = operations[method];
|
|
1793
|
+
const confirmationBodies = [];
|
|
1762
1794
|
if (operationItem) {
|
|
1763
1795
|
const operationId = operationItem.operationId;
|
|
1764
1796
|
const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1765
1797
|
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
1766
1798
|
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
|
+
}
|
|
1767
1823
|
let funcDescription = operationItem.description || operationItem.summary || "";
|
|
1768
1824
|
if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
|
|
1769
1825
|
warnings.push({
|
|
@@ -1797,66 +1853,19 @@ class ManifestUpdater {
|
|
|
1797
1853
|
}
|
|
1798
1854
|
}
|
|
1799
1855
|
if (options.allowConfirmation && method !== ConstantString.GetMethod) {
|
|
1800
|
-
|
|
1801
|
-
|
|
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
|
-
}
|
|
1856
|
+
if (!funcObj.capabilities) {
|
|
1857
|
+
funcObj.capabilities = {};
|
|
1824
1858
|
}
|
|
1859
|
+
funcObj.capabilities.confirmation = {
|
|
1860
|
+
type: "AdaptiveCard",
|
|
1861
|
+
title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
|
|
1862
|
+
};
|
|
1825
1863
|
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
|
-
};
|
|
1833
1864
|
funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
|
|
1834
1865
|
}
|
|
1835
1866
|
}
|
|
1836
1867
|
functions.push(funcObj);
|
|
1837
|
-
|
|
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
|
-
}
|
|
1868
|
+
functionNames.push(safeFunctionName);
|
|
1860
1869
|
const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
|
|
1861
1870
|
if (conversationStarterStr) {
|
|
1862
1871
|
conversationStarters.push(conversationStarterStr);
|
|
@@ -1866,12 +1875,6 @@ class ManifestUpdater {
|
|
|
1866
1875
|
}
|
|
1867
1876
|
}
|
|
1868
1877
|
}
|
|
1869
|
-
if (Object.keys(functionNamesMap).length === 0) {
|
|
1870
|
-
functionNamesMap["None"] = {
|
|
1871
|
-
functionNames: [],
|
|
1872
|
-
authName: "None",
|
|
1873
|
-
};
|
|
1874
|
-
}
|
|
1875
1878
|
let apiPlugin;
|
|
1876
1879
|
if (await fs.pathExists(apiPluginFilePath)) {
|
|
1877
1880
|
apiPlugin = await fs.readJSON(apiPluginFilePath);
|
|
@@ -1907,35 +1910,24 @@ class ManifestUpdater {
|
|
|
1907
1910
|
const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
|
|
1908
1911
|
apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
|
|
1909
1912
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === authType;
|
|
1913
|
+
const index = apiPlugin.runtimes.findIndex((runtime) => {
|
|
1914
|
+
var _a, _b;
|
|
1915
|
+
return runtime.spec.url === specRelativePath &&
|
|
1916
|
+
runtime.type === "OpenApi" &&
|
|
1917
|
+
((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === pluginAuthObj.type;
|
|
1918
|
+
});
|
|
1919
|
+
if (index === -1) {
|
|
1920
|
+
apiPlugin.runtimes.push({
|
|
1921
|
+
type: "OpenApi",
|
|
1922
|
+
auth: pluginAuthObj,
|
|
1923
|
+
spec: {
|
|
1924
|
+
url: specRelativePath,
|
|
1925
|
+
},
|
|
1926
|
+
run_for_functions: functionNames,
|
|
1925
1927
|
});
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
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
|
-
}
|
|
1928
|
+
}
|
|
1929
|
+
else {
|
|
1930
|
+
apiPlugin.runtimes[index].run_for_functions = functionNames;
|
|
1939
1931
|
}
|
|
1940
1932
|
if (!apiPlugin.name_for_human) {
|
|
1941
1933
|
apiPlugin.name_for_human = appName;
|
|
@@ -1976,7 +1968,7 @@ class ManifestUpdater {
|
|
|
1976
1968
|
};
|
|
1977
1969
|
if (authInfo) {
|
|
1978
1970
|
const auth = authInfo.authScheme;
|
|
1979
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
1971
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
|
|
1980
1972
|
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1981
1973
|
composeExtension.authorization = {
|
|
1982
1974
|
authType: "apiSecretServiceAuth",
|
|
@@ -2103,7 +2095,6 @@ class SpecParser {
|
|
|
2103
2095
|
};
|
|
2104
2096
|
this.pathOrSpec = pathOrDoc;
|
|
2105
2097
|
this.parser = new SwaggerParser();
|
|
2106
|
-
this.refParser = new $RefParser();
|
|
2107
2098
|
this.options = Object.assign(Object.assign({}, this.defaultOptions), (options !== null && options !== void 0 ? options : {}));
|
|
2108
2099
|
}
|
|
2109
2100
|
/**
|
|
@@ -2116,15 +2107,12 @@ class SpecParser {
|
|
|
2116
2107
|
let hash = "";
|
|
2117
2108
|
try {
|
|
2118
2109
|
await this.loadSpec();
|
|
2119
|
-
if (!this.
|
|
2110
|
+
if (!this.parser.$refs.circular) {
|
|
2120
2111
|
await this.parser.validate(this.spec);
|
|
2121
2112
|
}
|
|
2122
2113
|
else {
|
|
2123
|
-
// The following code hangs for Graph API, support will be added when SwaggerParser is updated.
|
|
2124
|
-
/*
|
|
2125
2114
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2126
2115
|
await this.parser.validate(clonedUnResolveSpec);
|
|
2127
|
-
*/
|
|
2128
2116
|
}
|
|
2129
2117
|
}
|
|
2130
2118
|
catch (e) {
|
|
@@ -2152,7 +2140,7 @@ class SpecParser {
|
|
|
2152
2140
|
};
|
|
2153
2141
|
}
|
|
2154
2142
|
// Remote reference not supported
|
|
2155
|
-
const refPaths = this.
|
|
2143
|
+
const refPaths = this.parser.$refs.paths();
|
|
2156
2144
|
// refPaths [0] is the current spec file path
|
|
2157
2145
|
if (refPaths.length > 1) {
|
|
2158
2146
|
errors.push({
|
|
@@ -2281,7 +2269,7 @@ class SpecParser {
|
|
|
2281
2269
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
2282
2270
|
}
|
|
2283
2271
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
|
|
2284
|
-
const newSpec = await this.
|
|
2272
|
+
const newSpec = (await this.parser.dereference(clonedUnResolveSpec));
|
|
2285
2273
|
return [newUnResolvedSpec, newSpec];
|
|
2286
2274
|
}
|
|
2287
2275
|
catch (err) {
|
|
@@ -2291,10 +2279,6 @@ class SpecParser {
|
|
|
2291
2279
|
throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
|
|
2292
2280
|
}
|
|
2293
2281
|
}
|
|
2294
|
-
async deReferenceSpec(spec) {
|
|
2295
|
-
const result = await this.refParser.dereference(spec);
|
|
2296
|
-
return result;
|
|
2297
|
-
}
|
|
2298
2282
|
/**
|
|
2299
2283
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
2300
2284
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
@@ -2311,6 +2295,7 @@ class SpecParser {
|
|
|
2311
2295
|
const newSpecs = await this.getFilteredSpecs(filter, signal);
|
|
2312
2296
|
const newUnResolvedSpec = newSpecs[0];
|
|
2313
2297
|
const newSpec = newSpecs[1];
|
|
2298
|
+
const authInfo = Utils.getAuthInfo(newSpec);
|
|
2314
2299
|
const paths = newUnResolvedSpec.paths;
|
|
2315
2300
|
for (const pathUrl in paths) {
|
|
2316
2301
|
const operations = paths[pathUrl];
|
|
@@ -2318,22 +2303,15 @@ class SpecParser {
|
|
|
2318
2303
|
const operationItem = operations[method];
|
|
2319
2304
|
const operationId = operationItem.operationId;
|
|
2320
2305
|
const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
|
|
2321
|
-
if (containsSpecialCharacters) {
|
|
2322
|
-
|
|
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
|
-
});
|
|
2306
|
+
if (!containsSpecialCharacters) {
|
|
2307
|
+
continue;
|
|
2336
2308
|
}
|
|
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
|
+
});
|
|
2337
2315
|
}
|
|
2338
2316
|
}
|
|
2339
2317
|
await this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
|
|
@@ -2346,8 +2324,7 @@ class SpecParser {
|
|
|
2346
2324
|
specPath: this.pathOrSpec,
|
|
2347
2325
|
}
|
|
2348
2326
|
: undefined;
|
|
2349
|
-
const
|
|
2350
|
-
const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authMap, existingPluginManifestInfo);
|
|
2327
|
+
const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authInfo, existingPluginManifestInfo);
|
|
2351
2328
|
result.warnings.push(...warnings);
|
|
2352
2329
|
await fs.outputJSON(manifestPath, updatedManifest, { spaces: 4 });
|
|
2353
2330
|
await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
|
|
@@ -2435,7 +2412,7 @@ class SpecParser {
|
|
|
2435
2412
|
this.isSwaggerFile = true;
|
|
2436
2413
|
}
|
|
2437
2414
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2438
|
-
this.spec = await this.
|
|
2415
|
+
this.spec = (await this.parser.dereference(clonedUnResolveSpec));
|
|
2439
2416
|
}
|
|
2440
2417
|
}
|
|
2441
2418
|
getAPIs(spec) {
|