@microsoft/m365-spec-parser 0.2.3 → 0.2.4-alpha.396238b05.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 +343 -253
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +467 -328
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +343 -253
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +467 -328
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/adaptiveCardGenerator.d.ts +5 -3
- package/dist/src/constants.d.ts +5 -4
- package/dist/src/interfaces.d.ts +12 -3
- package/dist/src/jsonDataGenerator.d.ts +6 -0
- package/dist/src/manifestUpdater.d.ts +3 -3
- package/dist/src/utils.d.ts +7 -4
- package/package.json +3 -3
package/dist/index.node.cjs.js
CHANGED
|
@@ -80,11 +80,8 @@ exports.ErrorType = void 0;
|
|
|
80
80
|
ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
|
|
81
81
|
ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
|
|
82
82
|
ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
|
|
83
|
-
ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
|
|
84
83
|
ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
|
|
85
84
|
ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
|
|
86
|
-
ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
|
|
87
|
-
ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
|
|
88
85
|
ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
|
|
89
86
|
ErrorType["NoParameter"] = "no-parameter";
|
|
90
87
|
ErrorType["NoAPIInfo"] = "no-api-info";
|
|
@@ -103,6 +100,9 @@ exports.WarningType = void 0;
|
|
|
103
100
|
WarningType["OperationOnlyContainsOptionalParam"] = "operation-only-contains-optional-param";
|
|
104
101
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
105
102
|
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
103
|
+
WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
|
|
104
|
+
WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
|
|
105
|
+
WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
106
106
|
WarningType["Unknown"] = "unknown";
|
|
107
107
|
})(exports.WarningType || (exports.WarningType = {}));
|
|
108
108
|
/**
|
|
@@ -140,25 +140,23 @@ ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converte
|
|
|
140
140
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
141
141
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
142
142
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
143
|
+
ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
|
|
144
|
+
ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
|
|
143
145
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
144
146
|
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.";
|
|
147
|
+
ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
|
|
145
148
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
146
149
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
147
150
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
148
151
|
ConstantString.GetMethod = "get";
|
|
149
152
|
ConstantString.PostMethod = "post";
|
|
150
153
|
ConstantString.AdaptiveCardVersion = "1.5";
|
|
151
|
-
ConstantString.AdaptiveCardSchema = "
|
|
154
|
+
ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
|
|
152
155
|
ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
153
156
|
ConstantString.TextBlockType = "TextBlock";
|
|
154
157
|
ConstantString.ImageType = "Image";
|
|
155
158
|
ConstantString.ContainerType = "Container";
|
|
156
|
-
ConstantString.RegistrationIdPostfix =
|
|
157
|
-
apiKey: "REGISTRATION_ID",
|
|
158
|
-
oauth2: "CONFIGURATION_ID",
|
|
159
|
-
http: "REGISTRATION_ID",
|
|
160
|
-
openIdConnect: "REGISTRATION_ID",
|
|
161
|
-
};
|
|
159
|
+
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
162
160
|
ConstantString.ResponseCodeFor20X = [
|
|
163
161
|
"200",
|
|
164
162
|
"201",
|
|
@@ -235,16 +233,8 @@ class SpecParserError extends Error {
|
|
|
235
233
|
|
|
236
234
|
// Copyright (c) Microsoft Corporation.
|
|
237
235
|
class Utils {
|
|
238
|
-
static
|
|
239
|
-
|
|
240
|
-
for (const property in schema.properties) {
|
|
241
|
-
const nestedSchema = schema.properties[property];
|
|
242
|
-
if (nestedSchema.type === "object") {
|
|
243
|
-
return true;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return false;
|
|
236
|
+
static isObjectSchema(schema) {
|
|
237
|
+
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
248
238
|
}
|
|
249
239
|
static containMultipleMediaTypes(bodyObject) {
|
|
250
240
|
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
@@ -255,11 +245,32 @@ class Utils {
|
|
|
255
245
|
static isAPIKeyAuth(authScheme) {
|
|
256
246
|
return authScheme.type === "apiKey";
|
|
257
247
|
}
|
|
248
|
+
static isAPIKeyAuthButNotInCookie(authScheme) {
|
|
249
|
+
return authScheme.type === "apiKey" && authScheme.in !== "cookie";
|
|
250
|
+
}
|
|
258
251
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
259
252
|
return !!(authScheme.type === "oauth2" &&
|
|
260
253
|
authScheme.flows &&
|
|
261
254
|
authScheme.flows.authorizationCode);
|
|
262
255
|
}
|
|
256
|
+
static isNotSupportedAuth(authSchemeArray) {
|
|
257
|
+
if (authSchemeArray.length === 0) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
for (const auths of authSchemeArray) {
|
|
264
|
+
if (auths.length === 1) {
|
|
265
|
+
if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
|
|
266
|
+
Utils.isBearerTokenAuth(auths[0].authScheme) ||
|
|
267
|
+
Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
263
274
|
static getAuthArray(securities, spec) {
|
|
264
275
|
var _a;
|
|
265
276
|
const result = [];
|
|
@@ -284,6 +295,20 @@ class Utils {
|
|
|
284
295
|
result.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
285
296
|
return result;
|
|
286
297
|
}
|
|
298
|
+
static getAuthMap(spec) {
|
|
299
|
+
const authMap = {};
|
|
300
|
+
for (const url in spec.paths) {
|
|
301
|
+
for (const method in spec.paths[url]) {
|
|
302
|
+
const operation = spec.paths[url][method];
|
|
303
|
+
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
304
|
+
if (authArray && authArray.length > 0) {
|
|
305
|
+
const currentAuth = authArray[0][0];
|
|
306
|
+
authMap[operation.operationId] = currentAuth;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return authMap;
|
|
311
|
+
}
|
|
287
312
|
static getAuthInfo(spec) {
|
|
288
313
|
let authInfo = undefined;
|
|
289
314
|
for (const url in spec.paths) {
|
|
@@ -312,27 +337,33 @@ class Utils {
|
|
|
312
337
|
let multipleMediaType = false;
|
|
313
338
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
314
339
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
315
|
-
if (responseObject
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
else {
|
|
328
|
-
return { json, multipleMediaType };
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
340
|
+
if (!responseObject) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
|
|
344
|
+
if (!allowMultipleMediaType && multipleMediaType) {
|
|
345
|
+
json = {};
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
const mediaObj = Utils.getJsonContentType(responseObject);
|
|
349
|
+
if (Object.keys(mediaObj).length > 0) {
|
|
350
|
+
json = mediaObj;
|
|
351
|
+
return { json, multipleMediaType };
|
|
332
352
|
}
|
|
333
353
|
}
|
|
334
354
|
return { json, multipleMediaType };
|
|
335
355
|
}
|
|
356
|
+
static getJsonContentType(responseObject) {
|
|
357
|
+
if (responseObject.content) {
|
|
358
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
359
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
360
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
361
|
+
return responseObject.content[contentType];
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return {};
|
|
366
|
+
}
|
|
336
367
|
static convertPathToCamelCase(path) {
|
|
337
368
|
const pathSegments = path.split(/[./{]/);
|
|
338
369
|
const camelCaseSegments = pathSegments.map((segment) => {
|
|
@@ -368,7 +399,7 @@ class Utils {
|
|
|
368
399
|
}
|
|
369
400
|
return newStr;
|
|
370
401
|
}
|
|
371
|
-
static checkServerUrl(servers) {
|
|
402
|
+
static checkServerUrl(servers, allowHttp = false) {
|
|
372
403
|
const errors = [];
|
|
373
404
|
let serverUrl;
|
|
374
405
|
try {
|
|
@@ -391,8 +422,7 @@ class Utils {
|
|
|
391
422
|
data: servers,
|
|
392
423
|
});
|
|
393
424
|
}
|
|
394
|
-
else if (protocol !== "https:") {
|
|
395
|
-
// Http server url is not supported
|
|
425
|
+
else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
|
|
396
426
|
const protocolString = protocol.slice(0, -1);
|
|
397
427
|
errors.push({
|
|
398
428
|
type: exports.ErrorType.UrlProtocolNotSupported,
|
|
@@ -408,10 +438,11 @@ class Utils {
|
|
|
408
438
|
let hasTopLevelServers = false;
|
|
409
439
|
let hasPathLevelServers = false;
|
|
410
440
|
let hasOperationLevelServers = false;
|
|
441
|
+
const allowHttp = options.projectType === exports.ProjectType.Copilot;
|
|
411
442
|
if (spec.servers && spec.servers.length >= 1) {
|
|
412
443
|
hasTopLevelServers = true;
|
|
413
444
|
// for multiple server, we only use the first url
|
|
414
|
-
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
445
|
+
const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
|
|
415
446
|
errors.push(...serverErrors);
|
|
416
447
|
}
|
|
417
448
|
const paths = spec.paths;
|
|
@@ -419,7 +450,7 @@ class Utils {
|
|
|
419
450
|
const methods = paths[path];
|
|
420
451
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
421
452
|
hasPathLevelServers = true;
|
|
422
|
-
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
453
|
+
const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
|
|
423
454
|
errors.push(...serverErrors);
|
|
424
455
|
}
|
|
425
456
|
for (const method in methods) {
|
|
@@ -427,7 +458,7 @@ class Utils {
|
|
|
427
458
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
428
459
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
429
460
|
hasOperationLevelServers = true;
|
|
430
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
461
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
|
|
431
462
|
errors.push(...serverErrors);
|
|
432
463
|
}
|
|
433
464
|
}
|
|
@@ -474,7 +505,7 @@ class Utils {
|
|
|
474
505
|
optionalParams.push(parameter);
|
|
475
506
|
}
|
|
476
507
|
}
|
|
477
|
-
else if (schema
|
|
508
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
478
509
|
const { properties } = schema;
|
|
479
510
|
for (const property in properties) {
|
|
480
511
|
let isRequired = false;
|
|
@@ -588,29 +619,6 @@ class Utils {
|
|
|
588
619
|
const serverUrl = operationServer || methodServer || rootServer;
|
|
589
620
|
return serverUrl;
|
|
590
621
|
}
|
|
591
|
-
static limitACBodyProperties(body, maxCount) {
|
|
592
|
-
const result = [];
|
|
593
|
-
let currentCount = 0;
|
|
594
|
-
for (const element of body) {
|
|
595
|
-
if (element.type === ConstantString.ContainerType) {
|
|
596
|
-
const items = this.limitACBodyProperties(element.items, maxCount - currentCount);
|
|
597
|
-
result.push({
|
|
598
|
-
type: ConstantString.ContainerType,
|
|
599
|
-
$data: element.$data,
|
|
600
|
-
items: items,
|
|
601
|
-
});
|
|
602
|
-
currentCount += items.length;
|
|
603
|
-
}
|
|
604
|
-
else {
|
|
605
|
-
result.push(element);
|
|
606
|
-
currentCount++;
|
|
607
|
-
}
|
|
608
|
-
if (currentCount >= maxCount) {
|
|
609
|
-
break;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
return result;
|
|
613
|
-
}
|
|
614
622
|
}
|
|
615
623
|
|
|
616
624
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -739,22 +747,6 @@ class Validator {
|
|
|
739
747
|
}
|
|
740
748
|
return result;
|
|
741
749
|
}
|
|
742
|
-
validateResponse(method, path) {
|
|
743
|
-
const result = { isValid: true, reason: [] };
|
|
744
|
-
const operationObject = this.spec.paths[path][method];
|
|
745
|
-
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
746
|
-
if (this.options.projectType === exports.ProjectType.SME) {
|
|
747
|
-
// only support response body only contains “application/json” content type
|
|
748
|
-
if (multipleMediaType) {
|
|
749
|
-
result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
|
|
750
|
-
}
|
|
751
|
-
else if (Object.keys(json).length === 0) {
|
|
752
|
-
// response body should not be empty
|
|
753
|
-
result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
return result;
|
|
757
|
-
}
|
|
758
750
|
validateServer(method, path) {
|
|
759
751
|
const result = { isValid: true, reason: [] };
|
|
760
752
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -763,8 +755,8 @@ class Validator {
|
|
|
763
755
|
result.reason.push(exports.ErrorType.NoServerInformation);
|
|
764
756
|
}
|
|
765
757
|
else {
|
|
766
|
-
|
|
767
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
758
|
+
const allowHttp = this.projectType === exports.ProjectType.Copilot;
|
|
759
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
|
|
768
760
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
769
761
|
}
|
|
770
762
|
return result;
|
|
@@ -787,6 +779,9 @@ class Validator {
|
|
|
787
779
|
reason: [exports.ErrorType.MultipleAuthNotSupported],
|
|
788
780
|
};
|
|
789
781
|
}
|
|
782
|
+
if (this.projectType === exports.ProjectType.Copilot) {
|
|
783
|
+
return { isValid: true, reason: [] };
|
|
784
|
+
}
|
|
790
785
|
for (const auths of authSchemeArray) {
|
|
791
786
|
if (auths.length === 1) {
|
|
792
787
|
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
@@ -799,125 +794,6 @@ class Validator {
|
|
|
799
794
|
}
|
|
800
795
|
return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
|
|
801
796
|
}
|
|
802
|
-
checkPostBodySchema(schema, isRequired = false) {
|
|
803
|
-
var _a;
|
|
804
|
-
const paramResult = {
|
|
805
|
-
requiredNum: 0,
|
|
806
|
-
optionalNum: 0,
|
|
807
|
-
isValid: true,
|
|
808
|
-
reason: [],
|
|
809
|
-
};
|
|
810
|
-
if (Object.keys(schema).length === 0) {
|
|
811
|
-
return paramResult;
|
|
812
|
-
}
|
|
813
|
-
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
814
|
-
const isCopilot = this.projectType === exports.ProjectType.Copilot;
|
|
815
|
-
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
816
|
-
paramResult.isValid = false;
|
|
817
|
-
paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
|
|
818
|
-
return paramResult;
|
|
819
|
-
}
|
|
820
|
-
if (schema.type === "string" ||
|
|
821
|
-
schema.type === "integer" ||
|
|
822
|
-
schema.type === "boolean" ||
|
|
823
|
-
schema.type === "number") {
|
|
824
|
-
if (isRequiredWithoutDefault) {
|
|
825
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
826
|
-
}
|
|
827
|
-
else {
|
|
828
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
else if (schema.type === "object") {
|
|
832
|
-
const { properties } = schema;
|
|
833
|
-
for (const property in properties) {
|
|
834
|
-
let isRequired = false;
|
|
835
|
-
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
836
|
-
isRequired = true;
|
|
837
|
-
}
|
|
838
|
-
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
839
|
-
paramResult.requiredNum += result.requiredNum;
|
|
840
|
-
paramResult.optionalNum += result.optionalNum;
|
|
841
|
-
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
842
|
-
paramResult.reason.push(...result.reason);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
else {
|
|
846
|
-
if (isRequiredWithoutDefault && !isCopilot) {
|
|
847
|
-
paramResult.isValid = false;
|
|
848
|
-
paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
return paramResult;
|
|
852
|
-
}
|
|
853
|
-
checkParamSchema(paramObject) {
|
|
854
|
-
const paramResult = {
|
|
855
|
-
requiredNum: 0,
|
|
856
|
-
optionalNum: 0,
|
|
857
|
-
isValid: true,
|
|
858
|
-
reason: [],
|
|
859
|
-
};
|
|
860
|
-
if (!paramObject) {
|
|
861
|
-
return paramResult;
|
|
862
|
-
}
|
|
863
|
-
const isCopilot = this.projectType === exports.ProjectType.Copilot;
|
|
864
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
865
|
-
const param = paramObject[i];
|
|
866
|
-
const schema = param.schema;
|
|
867
|
-
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
868
|
-
paramResult.isValid = false;
|
|
869
|
-
paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
|
|
870
|
-
continue;
|
|
871
|
-
}
|
|
872
|
-
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
873
|
-
if (isCopilot) {
|
|
874
|
-
if (isRequiredWithoutDefault) {
|
|
875
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
876
|
-
}
|
|
877
|
-
else {
|
|
878
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
879
|
-
}
|
|
880
|
-
continue;
|
|
881
|
-
}
|
|
882
|
-
if (param.in === "header" || param.in === "cookie") {
|
|
883
|
-
if (isRequiredWithoutDefault) {
|
|
884
|
-
paramResult.isValid = false;
|
|
885
|
-
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
886
|
-
}
|
|
887
|
-
continue;
|
|
888
|
-
}
|
|
889
|
-
if (schema.type !== "boolean" &&
|
|
890
|
-
schema.type !== "string" &&
|
|
891
|
-
schema.type !== "number" &&
|
|
892
|
-
schema.type !== "integer") {
|
|
893
|
-
if (isRequiredWithoutDefault) {
|
|
894
|
-
paramResult.isValid = false;
|
|
895
|
-
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
896
|
-
}
|
|
897
|
-
continue;
|
|
898
|
-
}
|
|
899
|
-
if (param.in === "query" || param.in === "path") {
|
|
900
|
-
if (isRequiredWithoutDefault) {
|
|
901
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
902
|
-
}
|
|
903
|
-
else {
|
|
904
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
return paramResult;
|
|
909
|
-
}
|
|
910
|
-
hasNestedObjectInSchema(schema) {
|
|
911
|
-
if (schema.type === "object") {
|
|
912
|
-
for (const property in schema.properties) {
|
|
913
|
-
const nestedSchema = schema.properties[property];
|
|
914
|
-
if (nestedSchema.type === "object") {
|
|
915
|
-
return true;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
return false;
|
|
920
|
-
}
|
|
921
797
|
}
|
|
922
798
|
|
|
923
799
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -927,7 +803,6 @@ class CopilotValidator extends Validator {
|
|
|
927
803
|
this.projectType = exports.ProjectType.Copilot;
|
|
928
804
|
this.options = options;
|
|
929
805
|
this.spec = spec;
|
|
930
|
-
this.checkCircularReference();
|
|
931
806
|
}
|
|
932
807
|
validateSpec() {
|
|
933
808
|
const result = { errors: [], warnings: [] };
|
|
@@ -953,10 +828,6 @@ class CopilotValidator extends Validator {
|
|
|
953
828
|
if (!methodAndPathResult.isValid) {
|
|
954
829
|
return methodAndPathResult;
|
|
955
830
|
}
|
|
956
|
-
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
957
|
-
if (!circularReferenceResult.isValid) {
|
|
958
|
-
return circularReferenceResult;
|
|
959
|
-
}
|
|
960
831
|
const operationObject = this.spec.paths[path][method];
|
|
961
832
|
// validate auth
|
|
962
833
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -968,24 +839,6 @@ class CopilotValidator extends Validator {
|
|
|
968
839
|
// validate server
|
|
969
840
|
const validateServerResult = this.validateServer(method, path);
|
|
970
841
|
result.reason.push(...validateServerResult.reason);
|
|
971
|
-
// validate response
|
|
972
|
-
const validateResponseResult = this.validateResponse(method, path);
|
|
973
|
-
result.reason.push(...validateResponseResult.reason);
|
|
974
|
-
// validate requestBody
|
|
975
|
-
const requestBody = operationObject.requestBody;
|
|
976
|
-
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
977
|
-
if (requestJsonBody) {
|
|
978
|
-
const requestBodySchema = requestJsonBody.schema;
|
|
979
|
-
if (requestBodySchema.type !== "object") {
|
|
980
|
-
result.reason.push(exports.ErrorType.PostBodySchemaIsNotJson);
|
|
981
|
-
}
|
|
982
|
-
const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
983
|
-
result.reason.push(...requestBodyParamResult.reason);
|
|
984
|
-
}
|
|
985
|
-
// validate parameters
|
|
986
|
-
const paramObject = operationObject.parameters;
|
|
987
|
-
const paramResult = this.checkParamSchema(paramObject);
|
|
988
|
-
result.reason.push(...paramResult.reason);
|
|
989
842
|
if (result.reason.length > 0) {
|
|
990
843
|
result.isValid = false;
|
|
991
844
|
}
|
|
@@ -1077,6 +930,108 @@ class SMEValidator extends Validator {
|
|
|
1077
930
|
}
|
|
1078
931
|
return result;
|
|
1079
932
|
}
|
|
933
|
+
validateResponse(method, path) {
|
|
934
|
+
const result = { isValid: true, reason: [] };
|
|
935
|
+
const operationObject = this.spec.paths[path][method];
|
|
936
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
937
|
+
// only support response body only contains “application/json” content type
|
|
938
|
+
if (multipleMediaType) {
|
|
939
|
+
result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
|
|
940
|
+
}
|
|
941
|
+
else if (Object.keys(json).length === 0) {
|
|
942
|
+
// response body should not be empty
|
|
943
|
+
result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
|
|
944
|
+
}
|
|
945
|
+
return result;
|
|
946
|
+
}
|
|
947
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
948
|
+
var _a;
|
|
949
|
+
const paramResult = {
|
|
950
|
+
requiredNum: 0,
|
|
951
|
+
optionalNum: 0,
|
|
952
|
+
isValid: true,
|
|
953
|
+
reason: [],
|
|
954
|
+
};
|
|
955
|
+
if (Object.keys(schema).length === 0) {
|
|
956
|
+
return paramResult;
|
|
957
|
+
}
|
|
958
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
959
|
+
const isCopilot = this.projectType === exports.ProjectType.Copilot;
|
|
960
|
+
if (schema.type === "string" ||
|
|
961
|
+
schema.type === "integer" ||
|
|
962
|
+
schema.type === "boolean" ||
|
|
963
|
+
schema.type === "number") {
|
|
964
|
+
if (isRequiredWithoutDefault) {
|
|
965
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
966
|
+
}
|
|
967
|
+
else {
|
|
968
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
972
|
+
const { properties } = schema;
|
|
973
|
+
for (const property in properties) {
|
|
974
|
+
let isRequired = false;
|
|
975
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
976
|
+
isRequired = true;
|
|
977
|
+
}
|
|
978
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
979
|
+
paramResult.requiredNum += result.requiredNum;
|
|
980
|
+
paramResult.optionalNum += result.optionalNum;
|
|
981
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
982
|
+
paramResult.reason.push(...result.reason);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
else {
|
|
986
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
987
|
+
paramResult.isValid = false;
|
|
988
|
+
paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
return paramResult;
|
|
992
|
+
}
|
|
993
|
+
checkParamSchema(paramObject) {
|
|
994
|
+
const paramResult = {
|
|
995
|
+
requiredNum: 0,
|
|
996
|
+
optionalNum: 0,
|
|
997
|
+
isValid: true,
|
|
998
|
+
reason: [],
|
|
999
|
+
};
|
|
1000
|
+
if (!paramObject) {
|
|
1001
|
+
return paramResult;
|
|
1002
|
+
}
|
|
1003
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
1004
|
+
const param = paramObject[i];
|
|
1005
|
+
const schema = param.schema;
|
|
1006
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
1007
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
1008
|
+
if (isRequiredWithoutDefault) {
|
|
1009
|
+
paramResult.isValid = false;
|
|
1010
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
1011
|
+
}
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
1014
|
+
if (schema.type !== "boolean" &&
|
|
1015
|
+
schema.type !== "string" &&
|
|
1016
|
+
schema.type !== "number" &&
|
|
1017
|
+
schema.type !== "integer") {
|
|
1018
|
+
if (isRequiredWithoutDefault) {
|
|
1019
|
+
paramResult.isValid = false;
|
|
1020
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
1021
|
+
}
|
|
1022
|
+
continue;
|
|
1023
|
+
}
|
|
1024
|
+
if (param.in === "query" || param.in === "path") {
|
|
1025
|
+
if (isRequiredWithoutDefault) {
|
|
1026
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
1027
|
+
}
|
|
1028
|
+
else {
|
|
1029
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
return paramResult;
|
|
1034
|
+
}
|
|
1080
1035
|
validateParamCount(postBodyResult, paramResult) {
|
|
1081
1036
|
const result = { isValid: true, reason: [] };
|
|
1082
1037
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
@@ -1354,20 +1309,157 @@ class SpecFilter {
|
|
|
1354
1309
|
}
|
|
1355
1310
|
}
|
|
1356
1311
|
|
|
1312
|
+
// Copyright (c) Microsoft Corporation.
|
|
1313
|
+
class JsonDataGenerator {
|
|
1314
|
+
static generate(schema) {
|
|
1315
|
+
return this.generateMockData(schema);
|
|
1316
|
+
}
|
|
1317
|
+
static generateMockData(schema) {
|
|
1318
|
+
if (this.visitedSchemas.has(schema)) {
|
|
1319
|
+
return null; // Prevent circular reference
|
|
1320
|
+
}
|
|
1321
|
+
this.visitedSchemas.add(schema);
|
|
1322
|
+
let result;
|
|
1323
|
+
if (schema.anyOf) {
|
|
1324
|
+
// Select the first schema in anyOf
|
|
1325
|
+
const selectedSchema = schema.anyOf[0];
|
|
1326
|
+
result = this.generateMockData(selectedSchema);
|
|
1327
|
+
}
|
|
1328
|
+
else if (schema.oneOf) {
|
|
1329
|
+
// Select the first schema in oneOf
|
|
1330
|
+
const selectedSchema = schema.oneOf[0];
|
|
1331
|
+
result = this.generateMockData(selectedSchema);
|
|
1332
|
+
}
|
|
1333
|
+
else if (schema.allOf) {
|
|
1334
|
+
// merge all schemas in allOf
|
|
1335
|
+
result = {};
|
|
1336
|
+
for (const subschema of schema.allOf) {
|
|
1337
|
+
const data = this.generateMockData(subschema);
|
|
1338
|
+
result = Object.assign(Object.assign({}, result), data);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
else {
|
|
1342
|
+
switch (schema.type) {
|
|
1343
|
+
case "string":
|
|
1344
|
+
if (schema.example !== undefined) {
|
|
1345
|
+
result = schema.example;
|
|
1346
|
+
}
|
|
1347
|
+
else if (schema.format) {
|
|
1348
|
+
switch (schema.format) {
|
|
1349
|
+
case "date-time":
|
|
1350
|
+
result = "2024-11-01T05:25:43.593Z";
|
|
1351
|
+
break;
|
|
1352
|
+
case "email":
|
|
1353
|
+
result = "example@example.com";
|
|
1354
|
+
break;
|
|
1355
|
+
case "uuid":
|
|
1356
|
+
result = "123e4567-e89b-12d3-a456-426614174000";
|
|
1357
|
+
break;
|
|
1358
|
+
case "ipv4":
|
|
1359
|
+
result = "192.168.0.1";
|
|
1360
|
+
break;
|
|
1361
|
+
case "ipv6":
|
|
1362
|
+
result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
|
|
1363
|
+
break;
|
|
1364
|
+
default:
|
|
1365
|
+
result = "example string";
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
else {
|
|
1369
|
+
result = "example string";
|
|
1370
|
+
}
|
|
1371
|
+
break;
|
|
1372
|
+
case "number":
|
|
1373
|
+
if (schema.example !== undefined) {
|
|
1374
|
+
result = schema.example;
|
|
1375
|
+
}
|
|
1376
|
+
else if (schema.format) {
|
|
1377
|
+
switch (schema.format) {
|
|
1378
|
+
case "float":
|
|
1379
|
+
result = 3.14;
|
|
1380
|
+
break;
|
|
1381
|
+
case "double":
|
|
1382
|
+
result = 3.14159;
|
|
1383
|
+
break;
|
|
1384
|
+
default:
|
|
1385
|
+
result = 123;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
else {
|
|
1389
|
+
result = 123;
|
|
1390
|
+
}
|
|
1391
|
+
break;
|
|
1392
|
+
case "integer":
|
|
1393
|
+
if (schema.example !== undefined) {
|
|
1394
|
+
result = schema.example;
|
|
1395
|
+
}
|
|
1396
|
+
else if (schema.format) {
|
|
1397
|
+
switch (schema.format) {
|
|
1398
|
+
case "int32":
|
|
1399
|
+
result = 123456;
|
|
1400
|
+
break;
|
|
1401
|
+
case "int64":
|
|
1402
|
+
result = 123456789;
|
|
1403
|
+
break;
|
|
1404
|
+
default:
|
|
1405
|
+
result = 123;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
else {
|
|
1409
|
+
result = 123;
|
|
1410
|
+
}
|
|
1411
|
+
break;
|
|
1412
|
+
case "boolean":
|
|
1413
|
+
result = schema.example !== undefined ? schema.example : true;
|
|
1414
|
+
break;
|
|
1415
|
+
case "array":
|
|
1416
|
+
result = [this.generateMockData(schema.items)];
|
|
1417
|
+
break;
|
|
1418
|
+
case "object":
|
|
1419
|
+
result = {};
|
|
1420
|
+
if (schema.properties) {
|
|
1421
|
+
for (const key in schema.properties) {
|
|
1422
|
+
result[key] = this.generateMockData(schema.properties[key]);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
break;
|
|
1426
|
+
default:
|
|
1427
|
+
result = schema.example || null;
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
this.visitedSchemas.delete(schema);
|
|
1431
|
+
return result;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
JsonDataGenerator.visitedSchemas = new Set();
|
|
1435
|
+
|
|
1357
1436
|
// Copyright (c) Microsoft Corporation.
|
|
1358
1437
|
class AdaptiveCardGenerator {
|
|
1359
|
-
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
|
|
1438
|
+
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false, maxElementCount = Number.MAX_SAFE_INTEGER) {
|
|
1360
1439
|
try {
|
|
1361
1440
|
const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
|
|
1362
1441
|
let cardBody = [];
|
|
1442
|
+
let jsonData = {};
|
|
1443
|
+
const warnings = [];
|
|
1444
|
+
const operationId = operationItem.operationId;
|
|
1363
1445
|
let schema = json.schema;
|
|
1364
1446
|
let jsonPath = "$";
|
|
1365
1447
|
if (schema && Object.keys(schema).length > 0) {
|
|
1448
|
+
try {
|
|
1449
|
+
jsonData = JsonDataGenerator.generate(schema);
|
|
1450
|
+
}
|
|
1451
|
+
catch (err) {
|
|
1452
|
+
warnings.push({
|
|
1453
|
+
type: exports.WarningType.GenerateJsonDataFailed,
|
|
1454
|
+
content: Utils.format(ConstantString.GenerateJsonDataFailed, operationId, err.toString()),
|
|
1455
|
+
data: operationId,
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1366
1458
|
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
1367
1459
|
if (jsonPath !== "$") {
|
|
1368
1460
|
schema = schema.properties[jsonPath];
|
|
1369
1461
|
}
|
|
1370
|
-
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
1462
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "", "", maxElementCount);
|
|
1371
1463
|
}
|
|
1372
1464
|
// if no schema, try to use example value
|
|
1373
1465
|
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
@@ -1395,16 +1487,20 @@ class AdaptiveCardGenerator {
|
|
|
1395
1487
|
version: ConstantString.AdaptiveCardVersion,
|
|
1396
1488
|
body: cardBody,
|
|
1397
1489
|
};
|
|
1398
|
-
return [fullCard, jsonPath];
|
|
1490
|
+
return [fullCard, jsonPath, jsonData, warnings];
|
|
1399
1491
|
}
|
|
1400
1492
|
catch (err) {
|
|
1401
1493
|
throw new SpecParserError(err.toString(), exports.ErrorType.GenerateAdaptiveCardFailed);
|
|
1402
1494
|
}
|
|
1403
1495
|
}
|
|
1404
|
-
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
1496
|
+
static generateCardFromResponse(schema, name, parentArrayName = "", maxElementCount = Number.MAX_SAFE_INTEGER, counter = { count: 0 }) {
|
|
1497
|
+
if (counter.count >= maxElementCount) {
|
|
1498
|
+
return [];
|
|
1499
|
+
}
|
|
1405
1500
|
if (schema.type === "array") {
|
|
1406
1501
|
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
1407
1502
|
if (Object.keys(schema.items).length === 0) {
|
|
1503
|
+
counter.count++;
|
|
1408
1504
|
return [
|
|
1409
1505
|
{
|
|
1410
1506
|
type: ConstantString.TextBlockType,
|
|
@@ -1413,7 +1509,7 @@ class AdaptiveCardGenerator {
|
|
|
1413
1509
|
},
|
|
1414
1510
|
];
|
|
1415
1511
|
}
|
|
1416
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
1512
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name, maxElementCount, counter);
|
|
1417
1513
|
const template = {
|
|
1418
1514
|
type: ConstantString.ContainerType,
|
|
1419
1515
|
$data: name ? `\${${name}}` : "${$root}",
|
|
@@ -1423,11 +1519,11 @@ class AdaptiveCardGenerator {
|
|
|
1423
1519
|
return [template];
|
|
1424
1520
|
}
|
|
1425
1521
|
// some schema may not contain type but contain properties
|
|
1426
|
-
if (
|
|
1522
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1427
1523
|
const { properties } = schema;
|
|
1428
1524
|
const result = [];
|
|
1429
1525
|
for (const property in properties) {
|
|
1430
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
1526
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName, maxElementCount, counter);
|
|
1431
1527
|
result.push(...obj);
|
|
1432
1528
|
}
|
|
1433
1529
|
if (schema.additionalProperties) {
|
|
@@ -1440,6 +1536,7 @@ class AdaptiveCardGenerator {
|
|
|
1440
1536
|
schema.type === "integer" ||
|
|
1441
1537
|
schema.type === "boolean" ||
|
|
1442
1538
|
schema.type === "number") {
|
|
1539
|
+
counter.count++;
|
|
1443
1540
|
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1444
1541
|
// string in root: "ddd"
|
|
1445
1542
|
let text = "result: ${$root}";
|
|
@@ -1464,24 +1561,17 @@ class AdaptiveCardGenerator {
|
|
|
1464
1561
|
];
|
|
1465
1562
|
}
|
|
1466
1563
|
else {
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
{
|
|
1479
|
-
type: "Image",
|
|
1480
|
-
url: "${$data}",
|
|
1481
|
-
$when: "${$data != null && $data != ''}",
|
|
1482
|
-
},
|
|
1483
|
-
];
|
|
1484
|
-
}
|
|
1564
|
+
const url = name ? `\${${name}}` : "${$data}";
|
|
1565
|
+
const condition = name
|
|
1566
|
+
? `\${${name} != null && ${name} != ''}`
|
|
1567
|
+
: "${$data != null && $data != ''}";
|
|
1568
|
+
return [
|
|
1569
|
+
{
|
|
1570
|
+
type: "Image",
|
|
1571
|
+
url,
|
|
1572
|
+
$when: condition,
|
|
1573
|
+
},
|
|
1574
|
+
];
|
|
1485
1575
|
}
|
|
1486
1576
|
}
|
|
1487
1577
|
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
@@ -1491,7 +1581,7 @@ class AdaptiveCardGenerator {
|
|
|
1491
1581
|
}
|
|
1492
1582
|
// Find the first array property in the response schema object with the well-known name
|
|
1493
1583
|
static getResponseJsonPathFromSchema(schema) {
|
|
1494
|
-
if (
|
|
1584
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1495
1585
|
const { properties } = schema;
|
|
1496
1586
|
for (const property in properties) {
|
|
1497
1587
|
const schema = properties[property];
|
|
@@ -1643,7 +1733,7 @@ function inferProperties(card) {
|
|
|
1643
1733
|
|
|
1644
1734
|
// Copyright (c) Microsoft Corporation.
|
|
1645
1735
|
class ManifestUpdater {
|
|
1646
|
-
static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options,
|
|
1736
|
+
static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authMap, existingPluginManifestInfo) {
|
|
1647
1737
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1648
1738
|
const manifest = yield fs__default['default'].readJSON(manifestPath);
|
|
1649
1739
|
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
@@ -1674,7 +1764,7 @@ class ManifestUpdater {
|
|
|
1674
1764
|
}
|
|
1675
1765
|
const appName = this.removeEnvs(manifest.name.short);
|
|
1676
1766
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
1677
|
-
const [apiPlugin, warnings] = yield ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1767
|
+
const [apiPlugin, warnings] = yield ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo);
|
|
1678
1768
|
return [manifest, apiPlugin, warnings];
|
|
1679
1769
|
});
|
|
1680
1770
|
}
|
|
@@ -1697,29 +1787,14 @@ class ManifestUpdater {
|
|
|
1697
1787
|
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), exports.ErrorType.UpdateManifestFailed);
|
|
1698
1788
|
}
|
|
1699
1789
|
}
|
|
1700
|
-
static generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1790
|
+
static generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo) {
|
|
1701
1791
|
var _a, _b, _c, _d;
|
|
1702
1792
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1703
1793
|
const warnings = [];
|
|
1704
1794
|
const functions = [];
|
|
1705
|
-
const
|
|
1795
|
+
const functionNamesMap = {};
|
|
1706
1796
|
const conversationStarters = [];
|
|
1707
1797
|
const paths = spec.paths;
|
|
1708
|
-
const pluginAuthObj = {
|
|
1709
|
-
type: "None",
|
|
1710
|
-
};
|
|
1711
|
-
if (authInfo) {
|
|
1712
|
-
if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
|
|
1713
|
-
pluginAuthObj.type = "OAuthPluginVault";
|
|
1714
|
-
}
|
|
1715
|
-
else if (Utils.isBearerTokenAuth(authInfo.authScheme)) {
|
|
1716
|
-
pluginAuthObj.type = "ApiKeyPluginVault";
|
|
1717
|
-
}
|
|
1718
|
-
if (pluginAuthObj.type !== "None") {
|
|
1719
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
|
|
1720
|
-
pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
1723
1798
|
for (const pathUrl in paths) {
|
|
1724
1799
|
const pathItem = paths[pathUrl];
|
|
1725
1800
|
if (pathItem) {
|
|
@@ -1727,36 +1802,11 @@ class ManifestUpdater {
|
|
|
1727
1802
|
for (const method in operations) {
|
|
1728
1803
|
if (options.allowMethods.includes(method)) {
|
|
1729
1804
|
const operationItem = operations[method];
|
|
1730
|
-
const confirmationBodies = [];
|
|
1731
1805
|
if (operationItem) {
|
|
1732
1806
|
const operationId = operationItem.operationId;
|
|
1733
1807
|
const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1734
1808
|
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
1735
1809
|
const summary = operationItem.summary;
|
|
1736
|
-
const paramObject = operationItem.parameters;
|
|
1737
|
-
const requestBody = operationItem.requestBody;
|
|
1738
|
-
if (paramObject) {
|
|
1739
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
1740
|
-
const param = paramObject[i];
|
|
1741
|
-
const schema = param.schema;
|
|
1742
|
-
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1743
|
-
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
if (requestBody) {
|
|
1747
|
-
const requestJsonBody = requestBody.content["application/json"];
|
|
1748
|
-
const requestBodySchema = requestJsonBody.schema;
|
|
1749
|
-
if (requestBodySchema.type === "object") {
|
|
1750
|
-
for (const property in requestBodySchema.properties) {
|
|
1751
|
-
const schema = requestBodySchema.properties[property];
|
|
1752
|
-
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1753
|
-
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
else {
|
|
1757
|
-
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
1810
|
let funcDescription = operationItem.description || operationItem.summary || "";
|
|
1761
1811
|
if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
|
|
1762
1812
|
warnings.push({
|
|
@@ -1774,8 +1824,7 @@ class ManifestUpdater {
|
|
|
1774
1824
|
try {
|
|
1775
1825
|
const { json } = Utils.getResponseJson(operationItem);
|
|
1776
1826
|
if (json.schema) {
|
|
1777
|
-
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem);
|
|
1778
|
-
card.body = Utils.limitACBodyProperties(card.body, 5);
|
|
1827
|
+
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem, false, 5);
|
|
1779
1828
|
const responseSemantic = wrapResponseSemantics(card, jsonPath);
|
|
1780
1829
|
funcObj.capabilities = {
|
|
1781
1830
|
response_semantics: responseSemantic,
|
|
@@ -1791,19 +1840,66 @@ class ManifestUpdater {
|
|
|
1791
1840
|
}
|
|
1792
1841
|
}
|
|
1793
1842
|
if (options.allowConfirmation && method !== ConstantString.GetMethod) {
|
|
1794
|
-
|
|
1795
|
-
|
|
1843
|
+
const paramObject = operationItem.parameters;
|
|
1844
|
+
const requestBody = operationItem.requestBody;
|
|
1845
|
+
const confirmationBodies = [];
|
|
1846
|
+
if (paramObject) {
|
|
1847
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
1848
|
+
const param = paramObject[i];
|
|
1849
|
+
const schema = param.schema;
|
|
1850
|
+
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1851
|
+
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
if (requestBody) {
|
|
1855
|
+
const requestJsonBody = Utils.getJsonContentType(requestBody);
|
|
1856
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
1857
|
+
if (Utils.isObjectSchema(requestBodySchema)) {
|
|
1858
|
+
for (const property in requestBodySchema.properties) {
|
|
1859
|
+
const schema = requestBodySchema.properties[property];
|
|
1860
|
+
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1861
|
+
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
else {
|
|
1865
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
|
|
1866
|
+
}
|
|
1796
1867
|
}
|
|
1797
|
-
funcObj.capabilities.confirmation = {
|
|
1798
|
-
type: "AdaptiveCard",
|
|
1799
|
-
title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
|
|
1800
|
-
};
|
|
1801
1868
|
if (confirmationBodies.length > 0) {
|
|
1869
|
+
if (!funcObj.capabilities) {
|
|
1870
|
+
funcObj.capabilities = {};
|
|
1871
|
+
}
|
|
1872
|
+
funcObj.capabilities.confirmation = {
|
|
1873
|
+
type: "AdaptiveCard",
|
|
1874
|
+
title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
|
|
1875
|
+
};
|
|
1802
1876
|
funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
|
|
1803
1877
|
}
|
|
1804
1878
|
}
|
|
1805
1879
|
functions.push(funcObj);
|
|
1806
|
-
|
|
1880
|
+
const authInfo = authMap[operationId];
|
|
1881
|
+
let key = "None";
|
|
1882
|
+
let authName = "None";
|
|
1883
|
+
if (authInfo) {
|
|
1884
|
+
if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
|
|
1885
|
+
key = "OAuthPluginVault";
|
|
1886
|
+
authName = authInfo.name;
|
|
1887
|
+
}
|
|
1888
|
+
else if (Utils.isBearerTokenAuth(authInfo.authScheme) ||
|
|
1889
|
+
Utils.isAPIKeyAuthButNotInCookie(authInfo.authScheme)) {
|
|
1890
|
+
key = "ApiKeyPluginVault";
|
|
1891
|
+
authName = authInfo.name;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
if (functionNamesMap[key]) {
|
|
1895
|
+
functionNamesMap[key].functionNames.push(safeFunctionName);
|
|
1896
|
+
}
|
|
1897
|
+
else {
|
|
1898
|
+
functionNamesMap[key] = {
|
|
1899
|
+
functionNames: [safeFunctionName],
|
|
1900
|
+
authName: authName,
|
|
1901
|
+
};
|
|
1902
|
+
}
|
|
1807
1903
|
const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
|
|
1808
1904
|
if (conversationStarterStr) {
|
|
1809
1905
|
conversationStarters.push(conversationStarterStr);
|
|
@@ -1813,6 +1909,12 @@ class ManifestUpdater {
|
|
|
1813
1909
|
}
|
|
1814
1910
|
}
|
|
1815
1911
|
}
|
|
1912
|
+
if (Object.keys(functionNamesMap).length === 0) {
|
|
1913
|
+
functionNamesMap["None"] = {
|
|
1914
|
+
functionNames: [],
|
|
1915
|
+
authName: "None",
|
|
1916
|
+
};
|
|
1917
|
+
}
|
|
1816
1918
|
let apiPlugin;
|
|
1817
1919
|
if (yield fs__default['default'].pathExists(apiPluginFilePath)) {
|
|
1818
1920
|
apiPlugin = yield fs__default['default'].readJSON(apiPluginFilePath);
|
|
@@ -1848,24 +1950,35 @@ class ManifestUpdater {
|
|
|
1848
1950
|
const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
|
|
1849
1951
|
apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
|
|
1850
1952
|
}
|
|
1851
|
-
const
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1953
|
+
for (const authType in functionNamesMap) {
|
|
1954
|
+
const pluginAuthObj = {
|
|
1955
|
+
type: authType,
|
|
1956
|
+
};
|
|
1957
|
+
const authName = functionNamesMap[authType].authName;
|
|
1958
|
+
if (pluginAuthObj.type !== "None") {
|
|
1959
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authName}_${ConstantString.RegistrationIdPostfix}`);
|
|
1960
|
+
pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
|
|
1961
|
+
}
|
|
1962
|
+
const functionNamesInfo = functionNamesMap[authType];
|
|
1963
|
+
const index = apiPlugin.runtimes.findIndex((runtime) => {
|
|
1964
|
+
var _a, _b;
|
|
1965
|
+
return runtime.spec.url === specRelativePath &&
|
|
1966
|
+
runtime.type === "OpenApi" &&
|
|
1967
|
+
((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === authType;
|
|
1865
1968
|
});
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1969
|
+
if (index === -1) {
|
|
1970
|
+
apiPlugin.runtimes.push({
|
|
1971
|
+
type: "OpenApi",
|
|
1972
|
+
auth: pluginAuthObj,
|
|
1973
|
+
spec: {
|
|
1974
|
+
url: specRelativePath,
|
|
1975
|
+
},
|
|
1976
|
+
run_for_functions: functionNamesInfo.functionNames,
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
else {
|
|
1980
|
+
apiPlugin.runtimes[index].run_for_functions = functionNamesInfo.functionNames;
|
|
1981
|
+
}
|
|
1869
1982
|
}
|
|
1870
1983
|
if (!apiPlugin.name_for_human) {
|
|
1871
1984
|
apiPlugin.name_for_human = appName;
|
|
@@ -1908,7 +2021,7 @@ class ManifestUpdater {
|
|
|
1908
2021
|
};
|
|
1909
2022
|
if (authInfo) {
|
|
1910
2023
|
const auth = authInfo.authScheme;
|
|
1911
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix
|
|
2024
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
1912
2025
|
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1913
2026
|
composeExtension.authorization = {
|
|
1914
2027
|
authType: "apiSecretServiceAuth",
|
|
@@ -2247,7 +2360,31 @@ class SpecParser {
|
|
|
2247
2360
|
const newSpecs = yield this.getFilteredSpecs(filter, signal);
|
|
2248
2361
|
const newUnResolvedSpec = newSpecs[0];
|
|
2249
2362
|
const newSpec = newSpecs[1];
|
|
2250
|
-
const
|
|
2363
|
+
const paths = newUnResolvedSpec.paths;
|
|
2364
|
+
for (const pathUrl in paths) {
|
|
2365
|
+
const operations = paths[pathUrl];
|
|
2366
|
+
for (const method in operations) {
|
|
2367
|
+
const operationItem = operations[method];
|
|
2368
|
+
const operationId = operationItem.operationId;
|
|
2369
|
+
const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
|
|
2370
|
+
if (containsSpecialCharacters) {
|
|
2371
|
+
operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2372
|
+
result.warnings.push({
|
|
2373
|
+
type: exports.WarningType.OperationIdContainsSpecialCharacters,
|
|
2374
|
+
content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
|
|
2375
|
+
data: operationId,
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
const authArray = Utils.getAuthArray(operationItem.security, newSpec);
|
|
2379
|
+
if (Utils.isNotSupportedAuth(authArray)) {
|
|
2380
|
+
result.warnings.push({
|
|
2381
|
+
type: exports.WarningType.UnsupportedAuthType,
|
|
2382
|
+
content: Utils.format(ConstantString.AuthTypeIsNotSupported, operationId),
|
|
2383
|
+
data: operationId,
|
|
2384
|
+
});
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2251
2388
|
yield this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
|
|
2252
2389
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
2253
2390
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
@@ -2258,7 +2395,8 @@ class SpecParser {
|
|
|
2258
2395
|
specPath: this.pathOrSpec,
|
|
2259
2396
|
}
|
|
2260
2397
|
: undefined;
|
|
2261
|
-
const
|
|
2398
|
+
const authMap = Utils.getAuthMap(newSpec);
|
|
2399
|
+
const [updatedManifest, apiPlugin, warnings] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authMap, existingPluginManifestInfo);
|
|
2262
2400
|
result.warnings.push(...warnings);
|
|
2263
2401
|
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 4 });
|
|
2264
2402
|
yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
|
|
@@ -2301,13 +2439,14 @@ class SpecParser {
|
|
|
2301
2439
|
if (this.options.allowMethods.includes(method)) {
|
|
2302
2440
|
const operation = newSpec.paths[url][method];
|
|
2303
2441
|
try {
|
|
2304
|
-
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
2442
|
+
const [card, jsonPath, jsonData, warnings] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
2443
|
+
result.warnings.push(...warnings);
|
|
2305
2444
|
const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2306
2445
|
const fileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
|
|
2307
2446
|
const wrappedCard = wrapAdaptiveCard(card, jsonPath);
|
|
2308
2447
|
yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
|
|
2309
2448
|
const dataFileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
|
|
2310
|
-
yield fs__default['default'].outputJSON(dataFileName,
|
|
2449
|
+
yield fs__default['default'].outputJSON(dataFileName, jsonData, { spaces: 2 });
|
|
2311
2450
|
}
|
|
2312
2451
|
catch (err) {
|
|
2313
2452
|
result.allSuccess = false;
|