@microsoft/m365-spec-parser 0.1.1-alpha.8d8f5a0bb.0 → 0.1.1-alpha.a277dba4e.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 +96 -62
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +188 -124
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +96 -62
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +187 -123
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +4 -1
- package/dist/src/index.browser.d.ts +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/interfaces.d.ts +46 -19
- package/dist/src/manifestUpdater.d.ts +5 -5
- package/dist/src/specFilter.d.ts +2 -1
- package/dist/src/specParser.browser.d.ts +1 -1
- package/dist/src/specParser.d.ts +2 -3
- package/dist/src/utils.d.ts +17 -14
- package/package.json +3 -3
package/dist/index.node.cjs.js
CHANGED
|
@@ -61,7 +61,8 @@ exports.ErrorType = void 0;
|
|
|
61
61
|
ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
|
|
62
62
|
ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
|
|
63
63
|
ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
|
|
64
|
-
ErrorType["
|
|
64
|
+
ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
|
|
65
|
+
ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
|
|
65
66
|
ErrorType["ListFailed"] = "list-failed";
|
|
66
67
|
ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
|
|
67
68
|
ErrorType["FilterSpecFailed"] = "filter-spec-failed";
|
|
@@ -92,7 +93,13 @@ exports.ValidationStatus = void 0;
|
|
|
92
93
|
ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
|
|
93
94
|
ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
|
|
94
95
|
ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
|
|
95
|
-
})(exports.ValidationStatus || (exports.ValidationStatus = {}));
|
|
96
|
+
})(exports.ValidationStatus || (exports.ValidationStatus = {}));
|
|
97
|
+
exports.ProjectType = void 0;
|
|
98
|
+
(function (ProjectType) {
|
|
99
|
+
ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
|
|
100
|
+
ProjectType[ProjectType["SME"] = 1] = "SME";
|
|
101
|
+
ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
|
|
102
|
+
})(exports.ProjectType || (exports.ProjectType = {}));
|
|
96
103
|
|
|
97
104
|
// Copyright (c) Microsoft Corporation.
|
|
98
105
|
class ConstantString {
|
|
@@ -111,7 +118,8 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
|
|
|
111
118
|
ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
|
|
112
119
|
ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
|
|
113
120
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
114
|
-
ConstantString.
|
|
121
|
+
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
122
|
+
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
115
123
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
116
124
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
117
125
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
@@ -124,6 +132,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
|
124
132
|
ConstantString.TextBlockType = "TextBlock";
|
|
125
133
|
ConstantString.ContainerType = "Container";
|
|
126
134
|
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
135
|
+
ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
|
|
127
136
|
ConstantString.ResponseCodeFor20X = [
|
|
128
137
|
"200",
|
|
129
138
|
"201",
|
|
@@ -183,7 +192,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
|
|
|
183
192
|
ConstantString.CommandDescriptionMaxLens = 128;
|
|
184
193
|
ConstantString.ParameterDescriptionMaxLens = 128;
|
|
185
194
|
ConstantString.CommandTitleMaxLens = 32;
|
|
186
|
-
ConstantString.ParameterTitleMaxLens = 32;
|
|
195
|
+
ConstantString.ParameterTitleMaxLens = 32;
|
|
196
|
+
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
187
197
|
|
|
188
198
|
// Copyright (c) Microsoft Corporation.
|
|
189
199
|
class SpecParserError extends Error {
|
|
@@ -304,6 +314,9 @@ class Utils {
|
|
|
304
314
|
}
|
|
305
315
|
return paramResult;
|
|
306
316
|
}
|
|
317
|
+
static containMultipleMediaTypes(bodyObject) {
|
|
318
|
+
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
319
|
+
}
|
|
307
320
|
/**
|
|
308
321
|
* Checks if the given API is supported.
|
|
309
322
|
* @param {string} method - The HTTP method of the API.
|
|
@@ -318,32 +331,40 @@ class Utils {
|
|
|
318
331
|
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
319
332
|
* 6. only support request body with “application/json” content type
|
|
320
333
|
*/
|
|
321
|
-
static isSupportedApi(method, path, spec,
|
|
334
|
+
static isSupportedApi(method, path, spec, options) {
|
|
335
|
+
var _a;
|
|
322
336
|
const pathObj = spec.paths[path];
|
|
323
337
|
method = method.toLocaleLowerCase();
|
|
324
338
|
if (pathObj) {
|
|
325
|
-
if ((
|
|
326
|
-
pathObj[method]) {
|
|
339
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
|
|
327
340
|
const securities = pathObj[method].security;
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
341
|
+
const isTeamsAi = options.projectType === exports.ProjectType.TeamsAi;
|
|
342
|
+
const isCopilot = options.projectType === exports.ProjectType.Copilot;
|
|
343
|
+
// Teams AI project doesn't care about auth, it will use authProvider for user to implement
|
|
344
|
+
if (!isTeamsAi) {
|
|
345
|
+
const authArray = Utils.getAuthArray(securities, spec);
|
|
346
|
+
if (!Utils.isSupportedAuth(authArray, options)) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
331
349
|
}
|
|
332
350
|
const operationObject = pathObj[method];
|
|
333
|
-
if (!allowMissingId && !operationObject.operationId) {
|
|
351
|
+
if (!options.allowMissingId && !operationObject.operationId) {
|
|
334
352
|
return false;
|
|
335
353
|
}
|
|
336
354
|
const paramObject = operationObject.parameters;
|
|
337
355
|
const requestBody = operationObject.requestBody;
|
|
338
356
|
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
339
|
-
|
|
340
|
-
if (mediaTypesCount > 1) {
|
|
357
|
+
if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
|
|
341
358
|
return false;
|
|
342
359
|
}
|
|
343
|
-
const responseJson = Utils.getResponseJson(operationObject);
|
|
360
|
+
const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
|
|
344
361
|
if (Object.keys(responseJson).length === 0) {
|
|
345
362
|
return false;
|
|
346
363
|
}
|
|
364
|
+
// Teams AI project doesn't care about request parameters/body
|
|
365
|
+
if (isTeamsAi) {
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
347
368
|
let requestBodyParamResult = {
|
|
348
369
|
requiredNum: 0,
|
|
349
370
|
optionalNum: 0,
|
|
@@ -368,8 +389,9 @@ class Utils {
|
|
|
368
389
|
return true;
|
|
369
390
|
}
|
|
370
391
|
if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
|
|
371
|
-
if (allowMultipleParameters &&
|
|
372
|
-
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
392
|
+
if (options.allowMultipleParameters &&
|
|
393
|
+
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
394
|
+
ConstantString.SMERequiredParamsMaxNum) {
|
|
373
395
|
return true;
|
|
374
396
|
}
|
|
375
397
|
return false;
|
|
@@ -388,29 +410,20 @@ class Utils {
|
|
|
388
410
|
}
|
|
389
411
|
return false;
|
|
390
412
|
}
|
|
391
|
-
static isSupportedAuth(
|
|
392
|
-
if (
|
|
413
|
+
static isSupportedAuth(authSchemeArray, options) {
|
|
414
|
+
if (authSchemeArray.length === 0) {
|
|
393
415
|
return true;
|
|
394
416
|
}
|
|
395
|
-
if (allowAPIKeyAuth || allowOauth2) {
|
|
417
|
+
if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
|
|
396
418
|
// Currently we don't support multiple auth in one operation
|
|
397
|
-
if (
|
|
419
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
398
420
|
return false;
|
|
399
421
|
}
|
|
400
|
-
for (const auths of
|
|
422
|
+
for (const auths of authSchemeArray) {
|
|
401
423
|
if (auths.length === 1) {
|
|
402
|
-
if (
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
else if (!allowAPIKeyAuth &&
|
|
406
|
-
allowOauth2 &&
|
|
407
|
-
Utils.isBearerTokenAuth(auths[0].authSchema)) {
|
|
408
|
-
return true;
|
|
409
|
-
}
|
|
410
|
-
else if (allowAPIKeyAuth &&
|
|
411
|
-
allowOauth2 &&
|
|
412
|
-
(Utils.isAPIKeyAuth(auths[0].authSchema) ||
|
|
413
|
-
Utils.isBearerTokenAuth(auths[0].authSchema))) {
|
|
424
|
+
if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
425
|
+
(options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
|
|
426
|
+
(options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
|
|
414
427
|
return true;
|
|
415
428
|
}
|
|
416
429
|
}
|
|
@@ -418,13 +431,17 @@ class Utils {
|
|
|
418
431
|
}
|
|
419
432
|
return false;
|
|
420
433
|
}
|
|
421
|
-
static
|
|
422
|
-
return
|
|
434
|
+
static isBearerTokenAuth(authScheme) {
|
|
435
|
+
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
423
436
|
}
|
|
424
|
-
static
|
|
425
|
-
return
|
|
426
|
-
|
|
427
|
-
|
|
437
|
+
static isAPIKeyAuth(authScheme) {
|
|
438
|
+
return authScheme.type === "apiKey";
|
|
439
|
+
}
|
|
440
|
+
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
441
|
+
if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
return false;
|
|
428
445
|
}
|
|
429
446
|
static getAuthArray(securities, spec) {
|
|
430
447
|
var _a;
|
|
@@ -437,7 +454,7 @@ class Utils {
|
|
|
437
454
|
for (const name in security) {
|
|
438
455
|
const auth = securitySchemas[name];
|
|
439
456
|
authArray.push({
|
|
440
|
-
|
|
457
|
+
authScheme: auth,
|
|
441
458
|
name: name,
|
|
442
459
|
});
|
|
443
460
|
}
|
|
@@ -452,18 +469,19 @@ class Utils {
|
|
|
452
469
|
static updateFirstLetter(str) {
|
|
453
470
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
454
471
|
}
|
|
455
|
-
static getResponseJson(operationObject) {
|
|
472
|
+
static getResponseJson(operationObject, isTeamsAiProject = false) {
|
|
456
473
|
var _a, _b;
|
|
457
474
|
let json = {};
|
|
458
475
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
459
476
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
460
|
-
const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
|
|
461
|
-
if (mediaTypesCount > 1) {
|
|
462
|
-
return {};
|
|
463
|
-
}
|
|
464
477
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
465
478
|
json = responseObject.content["application/json"];
|
|
466
|
-
|
|
479
|
+
if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
|
|
480
|
+
json = {};
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
467
485
|
}
|
|
468
486
|
}
|
|
469
487
|
return json;
|
|
@@ -537,7 +555,7 @@ class Utils {
|
|
|
537
555
|
}
|
|
538
556
|
return errors;
|
|
539
557
|
}
|
|
540
|
-
static validateServer(spec,
|
|
558
|
+
static validateServer(spec, options) {
|
|
541
559
|
const errors = [];
|
|
542
560
|
let hasTopLevelServers = false;
|
|
543
561
|
let hasPathLevelServers = false;
|
|
@@ -558,7 +576,7 @@ class Utils {
|
|
|
558
576
|
}
|
|
559
577
|
for (const method in methods) {
|
|
560
578
|
const operationObject = methods[method];
|
|
561
|
-
if (Utils.isSupportedApi(method, path, spec,
|
|
579
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
562
580
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
563
581
|
hasOperationLevelServers = true;
|
|
564
582
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -601,6 +619,7 @@ class Utils {
|
|
|
601
619
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
602
620
|
}
|
|
603
621
|
if (isRequired && schema.default === undefined) {
|
|
622
|
+
parameter.isRequired = true;
|
|
604
623
|
requiredParams.push(parameter);
|
|
605
624
|
}
|
|
606
625
|
else {
|
|
@@ -645,7 +664,7 @@ class Utils {
|
|
|
645
664
|
param.value = schema.default;
|
|
646
665
|
}
|
|
647
666
|
}
|
|
648
|
-
static parseApiInfo(operationItem,
|
|
667
|
+
static parseApiInfo(operationItem, options) {
|
|
649
668
|
var _a, _b;
|
|
650
669
|
const requiredParams = [];
|
|
651
670
|
const optionalParams = [];
|
|
@@ -659,11 +678,12 @@ class Utils {
|
|
|
659
678
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
660
679
|
};
|
|
661
680
|
const schema = param.schema;
|
|
662
|
-
if (allowMultipleParameters && schema) {
|
|
681
|
+
if (options.allowMultipleParameters && schema) {
|
|
663
682
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
664
683
|
}
|
|
665
684
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
666
685
|
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
686
|
+
parameter.isRequired = true;
|
|
667
687
|
requiredParams.push(parameter);
|
|
668
688
|
}
|
|
669
689
|
else {
|
|
@@ -677,7 +697,7 @@ class Utils {
|
|
|
677
697
|
const requestJson = requestBody.content["application/json"];
|
|
678
698
|
if (Object.keys(requestJson).length !== 0) {
|
|
679
699
|
const schema = requestJson.schema;
|
|
680
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
700
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
681
701
|
requiredParams.push(...requiredP);
|
|
682
702
|
optionalParams.push(...optionalP);
|
|
683
703
|
}
|
|
@@ -708,14 +728,13 @@ class Utils {
|
|
|
708
728
|
}
|
|
709
729
|
return [command, warning];
|
|
710
730
|
}
|
|
711
|
-
static listSupportedAPIs(spec,
|
|
731
|
+
static listSupportedAPIs(spec, options) {
|
|
712
732
|
const paths = spec.paths;
|
|
713
733
|
const result = {};
|
|
714
734
|
for (const path in paths) {
|
|
715
735
|
const methods = paths[path];
|
|
716
736
|
for (const method in methods) {
|
|
717
|
-
|
|
718
|
-
if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot)) {
|
|
737
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
719
738
|
const operationObject = methods[method];
|
|
720
739
|
result[`${method.toUpperCase()} ${path}`] = operationObject;
|
|
721
740
|
}
|
|
@@ -723,7 +742,7 @@ class Utils {
|
|
|
723
742
|
}
|
|
724
743
|
return result;
|
|
725
744
|
}
|
|
726
|
-
static validateSpec(spec, parser, isSwaggerFile,
|
|
745
|
+
static validateSpec(spec, parser, isSwaggerFile, options) {
|
|
727
746
|
const errors = [];
|
|
728
747
|
const warnings = [];
|
|
729
748
|
if (isSwaggerFile) {
|
|
@@ -733,7 +752,7 @@ class Utils {
|
|
|
733
752
|
});
|
|
734
753
|
}
|
|
735
754
|
// Server validation
|
|
736
|
-
const serverErrors = Utils.validateServer(spec,
|
|
755
|
+
const serverErrors = Utils.validateServer(spec, options);
|
|
737
756
|
errors.push(...serverErrors);
|
|
738
757
|
// Remote reference not supported
|
|
739
758
|
const refPaths = parser.$refs.paths();
|
|
@@ -746,7 +765,7 @@ class Utils {
|
|
|
746
765
|
});
|
|
747
766
|
}
|
|
748
767
|
// No supported API
|
|
749
|
-
const apiMap = Utils.listSupportedAPIs(spec,
|
|
768
|
+
const apiMap = Utils.listSupportedAPIs(spec, options);
|
|
750
769
|
if (Object.keys(apiMap).length === 0) {
|
|
751
770
|
errors.push({
|
|
752
771
|
type: exports.ErrorType.NoSupportedApi,
|
|
@@ -798,18 +817,31 @@ class Utils {
|
|
|
798
817
|
}
|
|
799
818
|
return safeRegistrationIdEnvName;
|
|
800
819
|
}
|
|
820
|
+
static getAllAPICount(spec) {
|
|
821
|
+
let count = 0;
|
|
822
|
+
const paths = spec.paths;
|
|
823
|
+
for (const path in paths) {
|
|
824
|
+
const methods = paths[path];
|
|
825
|
+
for (const method in methods) {
|
|
826
|
+
if (ConstantString.AllOperationMethods.includes(method)) {
|
|
827
|
+
count++;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return count;
|
|
832
|
+
}
|
|
801
833
|
}
|
|
802
834
|
|
|
803
835
|
// Copyright (c) Microsoft Corporation.
|
|
804
836
|
class SpecFilter {
|
|
805
|
-
static specFilter(filter, unResolveSpec, resolvedSpec,
|
|
837
|
+
static specFilter(filter, unResolveSpec, resolvedSpec, options) {
|
|
806
838
|
try {
|
|
807
839
|
const newSpec = Object.assign({}, unResolveSpec);
|
|
808
840
|
const newPaths = {};
|
|
809
841
|
for (const filterItem of filter) {
|
|
810
842
|
const [method, path] = filterItem.split(" ");
|
|
811
843
|
const methodName = method.toLowerCase();
|
|
812
|
-
if (!Utils.isSupportedApi(methodName, path, resolvedSpec,
|
|
844
|
+
if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
|
|
813
845
|
continue;
|
|
814
846
|
}
|
|
815
847
|
if (!newPaths[path]) {
|
|
@@ -835,7 +867,7 @@ class SpecFilter {
|
|
|
835
867
|
|
|
836
868
|
// Copyright (c) Microsoft Corporation.
|
|
837
869
|
class ManifestUpdater {
|
|
838
|
-
static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec) {
|
|
870
|
+
static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
|
|
839
871
|
return __awaiter(this, void 0, void 0, function* () {
|
|
840
872
|
const manifest = yield fs__default['default'].readJSON(manifestPath);
|
|
841
873
|
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
@@ -846,7 +878,7 @@ class ManifestUpdater {
|
|
|
846
878
|
];
|
|
847
879
|
ManifestUpdater.updateManifestDescription(manifest, spec);
|
|
848
880
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
849
|
-
const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath);
|
|
881
|
+
const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
|
|
850
882
|
return [manifest, apiPlugin];
|
|
851
883
|
});
|
|
852
884
|
}
|
|
@@ -871,7 +903,7 @@ class ManifestUpdater {
|
|
|
871
903
|
}
|
|
872
904
|
return parameter;
|
|
873
905
|
}
|
|
874
|
-
static generatePluginManifestSchema(spec, specRelativePath) {
|
|
906
|
+
static generatePluginManifestSchema(spec, specRelativePath, options) {
|
|
875
907
|
var _a, _b, _c;
|
|
876
908
|
const functions = [];
|
|
877
909
|
const functionNames = [];
|
|
@@ -881,7 +913,7 @@ class ManifestUpdater {
|
|
|
881
913
|
if (pathItem) {
|
|
882
914
|
const operations = pathItem;
|
|
883
915
|
for (const method in operations) {
|
|
884
|
-
if (
|
|
916
|
+
if (options.allowMethods.includes(method)) {
|
|
885
917
|
const operationItem = operations[method];
|
|
886
918
|
if (operationItem) {
|
|
887
919
|
const operationId = operationItem.operationId;
|
|
@@ -954,44 +986,51 @@ class ManifestUpdater {
|
|
|
954
986
|
};
|
|
955
987
|
return apiPlugin;
|
|
956
988
|
}
|
|
957
|
-
static updateManifest(manifestPath, outputSpecPath,
|
|
989
|
+
static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
|
|
958
990
|
return __awaiter(this, void 0, void 0, function* () {
|
|
959
991
|
try {
|
|
960
992
|
const originalManifest = yield fs__default['default'].readJSON(manifestPath);
|
|
961
993
|
const updatedPart = {};
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
commands
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
994
|
+
updatedPart.composeExtensions = [];
|
|
995
|
+
let warnings = [];
|
|
996
|
+
if (options.projectType === exports.ProjectType.SME) {
|
|
997
|
+
const updateResult = yield ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
|
|
998
|
+
const commands = updateResult[0];
|
|
999
|
+
warnings = updateResult[1];
|
|
1000
|
+
const composeExtension = {
|
|
1001
|
+
composeExtensionType: "apiBased",
|
|
1002
|
+
apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
|
|
1003
|
+
commands: commands,
|
|
1004
|
+
};
|
|
1005
|
+
if (authInfo) {
|
|
1006
|
+
const auth = authInfo.authScheme;
|
|
1007
|
+
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1008
|
+
const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
1009
|
+
composeExtension.authorization = {
|
|
1010
|
+
authType: "apiSecretServiceAuth",
|
|
1011
|
+
apiSecretServiceAuthConfiguration: {
|
|
1012
|
+
apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
|
|
1013
|
+
},
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
|
|
1017
|
+
const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
|
|
1018
|
+
composeExtension.authorization = {
|
|
1019
|
+
authType: "oAuth2.0",
|
|
1020
|
+
oAuthConfiguration: {
|
|
1021
|
+
oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
|
|
1022
|
+
},
|
|
1023
|
+
};
|
|
1024
|
+
updatedPart.webApplicationInfo = {
|
|
1025
|
+
id: "${{AAD_APP_CLIENT_ID}}",
|
|
1026
|
+
resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
990
1029
|
}
|
|
1030
|
+
updatedPart.composeExtensions = [composeExtension];
|
|
991
1031
|
}
|
|
992
1032
|
updatedPart.description = originalManifest.description;
|
|
993
1033
|
ManifestUpdater.updateManifestDescription(updatedPart, spec);
|
|
994
|
-
updatedPart.composeExtensions = isMe === undefined || isMe === true ? [composeExtension] : [];
|
|
995
1034
|
const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
|
|
996
1035
|
return [updatedManifest, warnings];
|
|
997
1036
|
}
|
|
@@ -1000,7 +1039,8 @@ class ManifestUpdater {
|
|
|
1000
1039
|
}
|
|
1001
1040
|
});
|
|
1002
1041
|
}
|
|
1003
|
-
static generateCommands(spec,
|
|
1042
|
+
static generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
|
|
1043
|
+
var _a;
|
|
1004
1044
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1005
1045
|
const paths = spec.paths;
|
|
1006
1046
|
const commands = [];
|
|
@@ -1012,14 +1052,16 @@ class ManifestUpdater {
|
|
|
1012
1052
|
const operations = pathItem;
|
|
1013
1053
|
// Currently only support GET and POST method
|
|
1014
1054
|
for (const method in operations) {
|
|
1015
|
-
if (
|
|
1055
|
+
if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
|
|
1016
1056
|
const operationItem = operations[method];
|
|
1017
1057
|
if (operationItem) {
|
|
1018
|
-
const [command, warning] = Utils.parseApiInfo(operationItem,
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1058
|
+
const [command, warning] = Utils.parseApiInfo(operationItem, options);
|
|
1059
|
+
if (adaptiveCardFolder) {
|
|
1060
|
+
const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
|
|
1061
|
+
command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
|
|
1062
|
+
? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
|
|
1063
|
+
: "";
|
|
1064
|
+
}
|
|
1023
1065
|
if (warning) {
|
|
1024
1066
|
warnings.push(warning);
|
|
1025
1067
|
}
|
|
@@ -1303,9 +1345,11 @@ class SpecParser {
|
|
|
1303
1345
|
allowMissingId: true,
|
|
1304
1346
|
allowSwagger: true,
|
|
1305
1347
|
allowAPIKeyAuth: false,
|
|
1348
|
+
allowBearerTokenAuth: false,
|
|
1306
1349
|
allowMultipleParameters: false,
|
|
1307
1350
|
allowOauth2: false,
|
|
1308
|
-
|
|
1351
|
+
allowMethods: ["get", "post"],
|
|
1352
|
+
projectType: exports.ProjectType.SME,
|
|
1309
1353
|
};
|
|
1310
1354
|
this.pathOrSpec = pathOrDoc;
|
|
1311
1355
|
this.parser = new SwaggerParser__default['default']();
|
|
@@ -1339,7 +1383,23 @@ class SpecParser {
|
|
|
1339
1383
|
],
|
|
1340
1384
|
};
|
|
1341
1385
|
}
|
|
1342
|
-
|
|
1386
|
+
if (this.options.projectType === exports.ProjectType.SME ||
|
|
1387
|
+
this.options.projectType === exports.ProjectType.Copilot) {
|
|
1388
|
+
if (this.spec.openapi >= "3.1.0") {
|
|
1389
|
+
return {
|
|
1390
|
+
status: exports.ValidationStatus.Error,
|
|
1391
|
+
warnings: [],
|
|
1392
|
+
errors: [
|
|
1393
|
+
{
|
|
1394
|
+
type: exports.ErrorType.SpecVersionNotSupported,
|
|
1395
|
+
content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
|
|
1396
|
+
data: this.spec.openapi,
|
|
1397
|
+
},
|
|
1398
|
+
],
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
|
|
1343
1403
|
}
|
|
1344
1404
|
catch (err) {
|
|
1345
1405
|
throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
|
|
@@ -1364,7 +1424,11 @@ class SpecParser {
|
|
|
1364
1424
|
yield this.loadSpec();
|
|
1365
1425
|
const spec = this.spec;
|
|
1366
1426
|
const apiMap = this.getAllSupportedAPIs(spec);
|
|
1367
|
-
const result =
|
|
1427
|
+
const result = {
|
|
1428
|
+
validAPIs: [],
|
|
1429
|
+
allAPICount: 0,
|
|
1430
|
+
validAPICount: 0,
|
|
1431
|
+
};
|
|
1368
1432
|
for (const apiKey in apiMap) {
|
|
1369
1433
|
const apiResult = {
|
|
1370
1434
|
api: "",
|
|
@@ -1389,13 +1453,15 @@ class SpecParser {
|
|
|
1389
1453
|
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1390
1454
|
for (const auths of authArray) {
|
|
1391
1455
|
if (auths.length === 1) {
|
|
1392
|
-
apiResult.auth = auths[0]
|
|
1456
|
+
apiResult.auth = auths[0];
|
|
1393
1457
|
break;
|
|
1394
1458
|
}
|
|
1395
1459
|
}
|
|
1396
1460
|
apiResult.api = apiKey;
|
|
1397
|
-
result.push(apiResult);
|
|
1461
|
+
result.validAPIs.push(apiResult);
|
|
1398
1462
|
}
|
|
1463
|
+
result.allAPICount = Utils.getAllAPICount(spec);
|
|
1464
|
+
result.validAPICount = result.validAPIs.length;
|
|
1399
1465
|
return result;
|
|
1400
1466
|
}
|
|
1401
1467
|
catch (err) {
|
|
@@ -1420,7 +1486,7 @@ class SpecParser {
|
|
|
1420
1486
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1421
1487
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1422
1488
|
}
|
|
1423
|
-
const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options
|
|
1489
|
+
const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
|
|
1424
1490
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1425
1491
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1426
1492
|
}
|
|
@@ -1463,7 +1529,7 @@ class SpecParser {
|
|
|
1463
1529
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1464
1530
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1465
1531
|
}
|
|
1466
|
-
const [updatedManifest, apiPlugin] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec);
|
|
1532
|
+
const [updatedManifest, apiPlugin] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
|
|
1467
1533
|
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1468
1534
|
yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
|
|
1469
1535
|
}
|
|
@@ -1482,9 +1548,8 @@ class SpecParser {
|
|
|
1482
1548
|
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1483
1549
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
1484
1550
|
* @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
|
|
1485
|
-
* @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
|
|
1486
1551
|
*/
|
|
1487
|
-
generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal
|
|
1552
|
+
generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
1488
1553
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1489
1554
|
const result = {
|
|
1490
1555
|
allSuccess: true,
|
|
@@ -1494,23 +1559,23 @@ class SpecParser {
|
|
|
1494
1559
|
const newSpecs = yield this.getFilteredSpecs(filter, signal);
|
|
1495
1560
|
const newUnResolvedSpec = newSpecs[0];
|
|
1496
1561
|
const newSpec = newSpecs[1];
|
|
1497
|
-
const
|
|
1498
|
-
let
|
|
1562
|
+
const authSet = new Set();
|
|
1563
|
+
let hasMultipleAuth = false;
|
|
1499
1564
|
for (const url in newSpec.paths) {
|
|
1500
1565
|
for (const method in newSpec.paths[url]) {
|
|
1501
1566
|
const operation = newSpec.paths[url][method];
|
|
1502
1567
|
const authArray = Utils.getAuthArray(operation.security, newSpec);
|
|
1503
1568
|
if (authArray && authArray.length > 0) {
|
|
1504
|
-
|
|
1505
|
-
if (
|
|
1506
|
-
|
|
1569
|
+
authSet.add(authArray[0][0]);
|
|
1570
|
+
if (authSet.size > 1) {
|
|
1571
|
+
hasMultipleAuth = true;
|
|
1507
1572
|
break;
|
|
1508
1573
|
}
|
|
1509
1574
|
}
|
|
1510
1575
|
}
|
|
1511
1576
|
}
|
|
1512
|
-
if (
|
|
1513
|
-
throw new SpecParserError(ConstantString.
|
|
1577
|
+
if (hasMultipleAuth && this.options.projectType !== exports.ProjectType.TeamsAi) {
|
|
1578
|
+
throw new SpecParserError(ConstantString.MultipleAuthNotSupported, exports.ErrorType.MultipleAuthNotSupported);
|
|
1514
1579
|
}
|
|
1515
1580
|
let resultStr;
|
|
1516
1581
|
if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
|
|
@@ -1520,12 +1585,11 @@ class SpecParser {
|
|
|
1520
1585
|
resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
|
|
1521
1586
|
}
|
|
1522
1587
|
yield fs__default['default'].outputFile(outputSpecPath, resultStr);
|
|
1523
|
-
if (
|
|
1524
|
-
// Only generate adaptive card for Messaging Extension
|
|
1588
|
+
if (adaptiveCardFolder) {
|
|
1525
1589
|
for (const url in newSpec.paths) {
|
|
1526
1590
|
for (const method in newSpec.paths[url]) {
|
|
1527
|
-
// paths object may contain description/summary, so we need to check if it is a operation object
|
|
1528
|
-
if (
|
|
1591
|
+
// paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
|
|
1592
|
+
if (this.options.allowMethods.includes(method)) {
|
|
1529
1593
|
const operation = newSpec.paths[url][method];
|
|
1530
1594
|
try {
|
|
1531
1595
|
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
@@ -1550,8 +1614,8 @@ class SpecParser {
|
|
|
1550
1614
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1551
1615
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1552
1616
|
}
|
|
1553
|
-
const
|
|
1554
|
-
const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath,
|
|
1617
|
+
const authInfo = Array.from(authSet)[0];
|
|
1618
|
+
const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
|
|
1555
1619
|
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1556
1620
|
result.warnings.push(...warnings);
|
|
1557
1621
|
}
|
|
@@ -1583,7 +1647,7 @@ class SpecParser {
|
|
|
1583
1647
|
if (this.apiMap !== undefined) {
|
|
1584
1648
|
return this.apiMap;
|
|
1585
1649
|
}
|
|
1586
|
-
const result = Utils.listSupportedAPIs(spec, this.options
|
|
1650
|
+
const result = Utils.listSupportedAPIs(spec, this.options);
|
|
1587
1651
|
this.apiMap = result;
|
|
1588
1652
|
return result;
|
|
1589
1653
|
}
|