@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.esm2017.mjs
CHANGED
|
@@ -19,7 +19,8 @@ var ErrorType;
|
|
|
19
19
|
ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
|
|
20
20
|
ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
|
|
21
21
|
ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
|
|
22
|
-
ErrorType["
|
|
22
|
+
ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
|
|
23
|
+
ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
|
|
23
24
|
ErrorType["ListFailed"] = "list-failed";
|
|
24
25
|
ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
|
|
25
26
|
ErrorType["FilterSpecFailed"] = "filter-spec-failed";
|
|
@@ -50,7 +51,13 @@ var ValidationStatus;
|
|
|
50
51
|
ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
|
|
51
52
|
ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
|
|
52
53
|
ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
|
|
53
|
-
})(ValidationStatus || (ValidationStatus = {}));
|
|
54
|
+
})(ValidationStatus || (ValidationStatus = {}));
|
|
55
|
+
var ProjectType;
|
|
56
|
+
(function (ProjectType) {
|
|
57
|
+
ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
|
|
58
|
+
ProjectType[ProjectType["SME"] = 1] = "SME";
|
|
59
|
+
ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
|
|
60
|
+
})(ProjectType || (ProjectType = {}));
|
|
54
61
|
|
|
55
62
|
// Copyright (c) Microsoft Corporation.
|
|
56
63
|
class ConstantString {
|
|
@@ -69,7 +76,8 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
|
|
|
69
76
|
ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
|
|
70
77
|
ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
|
|
71
78
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
72
|
-
ConstantString.
|
|
79
|
+
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
80
|
+
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
73
81
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
74
82
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
75
83
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
@@ -82,6 +90,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
|
82
90
|
ConstantString.TextBlockType = "TextBlock";
|
|
83
91
|
ConstantString.ContainerType = "Container";
|
|
84
92
|
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
93
|
+
ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
|
|
85
94
|
ConstantString.ResponseCodeFor20X = [
|
|
86
95
|
"200",
|
|
87
96
|
"201",
|
|
@@ -141,7 +150,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
|
|
|
141
150
|
ConstantString.CommandDescriptionMaxLens = 128;
|
|
142
151
|
ConstantString.ParameterDescriptionMaxLens = 128;
|
|
143
152
|
ConstantString.CommandTitleMaxLens = 32;
|
|
144
|
-
ConstantString.ParameterTitleMaxLens = 32;
|
|
153
|
+
ConstantString.ParameterTitleMaxLens = 32;
|
|
154
|
+
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
145
155
|
|
|
146
156
|
// Copyright (c) Microsoft Corporation.
|
|
147
157
|
class SpecParserError extends Error {
|
|
@@ -262,6 +272,9 @@ class Utils {
|
|
|
262
272
|
}
|
|
263
273
|
return paramResult;
|
|
264
274
|
}
|
|
275
|
+
static containMultipleMediaTypes(bodyObject) {
|
|
276
|
+
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
277
|
+
}
|
|
265
278
|
/**
|
|
266
279
|
* Checks if the given API is supported.
|
|
267
280
|
* @param {string} method - The HTTP method of the API.
|
|
@@ -276,32 +289,40 @@ class Utils {
|
|
|
276
289
|
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
277
290
|
* 6. only support request body with “application/json” content type
|
|
278
291
|
*/
|
|
279
|
-
static isSupportedApi(method, path, spec,
|
|
292
|
+
static isSupportedApi(method, path, spec, options) {
|
|
293
|
+
var _a;
|
|
280
294
|
const pathObj = spec.paths[path];
|
|
281
295
|
method = method.toLocaleLowerCase();
|
|
282
296
|
if (pathObj) {
|
|
283
|
-
if ((
|
|
284
|
-
pathObj[method]) {
|
|
297
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
|
|
285
298
|
const securities = pathObj[method].security;
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
299
|
+
const isTeamsAi = options.projectType === ProjectType.TeamsAi;
|
|
300
|
+
const isCopilot = options.projectType === ProjectType.Copilot;
|
|
301
|
+
// Teams AI project doesn't care about auth, it will use authProvider for user to implement
|
|
302
|
+
if (!isTeamsAi) {
|
|
303
|
+
const authArray = Utils.getAuthArray(securities, spec);
|
|
304
|
+
if (!Utils.isSupportedAuth(authArray, options)) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
289
307
|
}
|
|
290
308
|
const operationObject = pathObj[method];
|
|
291
|
-
if (!allowMissingId && !operationObject.operationId) {
|
|
309
|
+
if (!options.allowMissingId && !operationObject.operationId) {
|
|
292
310
|
return false;
|
|
293
311
|
}
|
|
294
312
|
const paramObject = operationObject.parameters;
|
|
295
313
|
const requestBody = operationObject.requestBody;
|
|
296
314
|
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
297
|
-
|
|
298
|
-
if (mediaTypesCount > 1) {
|
|
315
|
+
if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
|
|
299
316
|
return false;
|
|
300
317
|
}
|
|
301
|
-
const responseJson = Utils.getResponseJson(operationObject);
|
|
318
|
+
const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
|
|
302
319
|
if (Object.keys(responseJson).length === 0) {
|
|
303
320
|
return false;
|
|
304
321
|
}
|
|
322
|
+
// Teams AI project doesn't care about request parameters/body
|
|
323
|
+
if (isTeamsAi) {
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
305
326
|
let requestBodyParamResult = {
|
|
306
327
|
requiredNum: 0,
|
|
307
328
|
optionalNum: 0,
|
|
@@ -326,8 +347,9 @@ class Utils {
|
|
|
326
347
|
return true;
|
|
327
348
|
}
|
|
328
349
|
if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
|
|
329
|
-
if (allowMultipleParameters &&
|
|
330
|
-
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
350
|
+
if (options.allowMultipleParameters &&
|
|
351
|
+
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
352
|
+
ConstantString.SMERequiredParamsMaxNum) {
|
|
331
353
|
return true;
|
|
332
354
|
}
|
|
333
355
|
return false;
|
|
@@ -346,29 +368,20 @@ class Utils {
|
|
|
346
368
|
}
|
|
347
369
|
return false;
|
|
348
370
|
}
|
|
349
|
-
static isSupportedAuth(
|
|
350
|
-
if (
|
|
371
|
+
static isSupportedAuth(authSchemeArray, options) {
|
|
372
|
+
if (authSchemeArray.length === 0) {
|
|
351
373
|
return true;
|
|
352
374
|
}
|
|
353
|
-
if (allowAPIKeyAuth || allowOauth2) {
|
|
375
|
+
if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
|
|
354
376
|
// Currently we don't support multiple auth in one operation
|
|
355
|
-
if (
|
|
377
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
356
378
|
return false;
|
|
357
379
|
}
|
|
358
|
-
for (const auths of
|
|
380
|
+
for (const auths of authSchemeArray) {
|
|
359
381
|
if (auths.length === 1) {
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
else if (!allowAPIKeyAuth &&
|
|
364
|
-
allowOauth2 &&
|
|
365
|
-
Utils.isBearerTokenAuth(auths[0].authSchema)) {
|
|
366
|
-
return true;
|
|
367
|
-
}
|
|
368
|
-
else if (allowAPIKeyAuth &&
|
|
369
|
-
allowOauth2 &&
|
|
370
|
-
(Utils.isAPIKeyAuth(auths[0].authSchema) ||
|
|
371
|
-
Utils.isBearerTokenAuth(auths[0].authSchema))) {
|
|
382
|
+
if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
383
|
+
(options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
|
|
384
|
+
(options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
|
|
372
385
|
return true;
|
|
373
386
|
}
|
|
374
387
|
}
|
|
@@ -376,13 +389,17 @@ class Utils {
|
|
|
376
389
|
}
|
|
377
390
|
return false;
|
|
378
391
|
}
|
|
379
|
-
static
|
|
380
|
-
return
|
|
392
|
+
static isBearerTokenAuth(authScheme) {
|
|
393
|
+
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
381
394
|
}
|
|
382
|
-
static
|
|
383
|
-
return
|
|
384
|
-
|
|
385
|
-
|
|
395
|
+
static isAPIKeyAuth(authScheme) {
|
|
396
|
+
return authScheme.type === "apiKey";
|
|
397
|
+
}
|
|
398
|
+
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
399
|
+
if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
return false;
|
|
386
403
|
}
|
|
387
404
|
static getAuthArray(securities, spec) {
|
|
388
405
|
var _a;
|
|
@@ -395,7 +412,7 @@ class Utils {
|
|
|
395
412
|
for (const name in security) {
|
|
396
413
|
const auth = securitySchemas[name];
|
|
397
414
|
authArray.push({
|
|
398
|
-
|
|
415
|
+
authScheme: auth,
|
|
399
416
|
name: name,
|
|
400
417
|
});
|
|
401
418
|
}
|
|
@@ -410,18 +427,19 @@ class Utils {
|
|
|
410
427
|
static updateFirstLetter(str) {
|
|
411
428
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
412
429
|
}
|
|
413
|
-
static getResponseJson(operationObject) {
|
|
430
|
+
static getResponseJson(operationObject, isTeamsAiProject = false) {
|
|
414
431
|
var _a, _b;
|
|
415
432
|
let json = {};
|
|
416
433
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
417
434
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
418
|
-
const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
|
|
419
|
-
if (mediaTypesCount > 1) {
|
|
420
|
-
return {};
|
|
421
|
-
}
|
|
422
435
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
423
436
|
json = responseObject.content["application/json"];
|
|
424
|
-
|
|
437
|
+
if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
|
|
438
|
+
json = {};
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
425
443
|
}
|
|
426
444
|
}
|
|
427
445
|
return json;
|
|
@@ -495,7 +513,7 @@ class Utils {
|
|
|
495
513
|
}
|
|
496
514
|
return errors;
|
|
497
515
|
}
|
|
498
|
-
static validateServer(spec,
|
|
516
|
+
static validateServer(spec, options) {
|
|
499
517
|
const errors = [];
|
|
500
518
|
let hasTopLevelServers = false;
|
|
501
519
|
let hasPathLevelServers = false;
|
|
@@ -516,7 +534,7 @@ class Utils {
|
|
|
516
534
|
}
|
|
517
535
|
for (const method in methods) {
|
|
518
536
|
const operationObject = methods[method];
|
|
519
|
-
if (Utils.isSupportedApi(method, path, spec,
|
|
537
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
520
538
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
521
539
|
hasOperationLevelServers = true;
|
|
522
540
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -559,6 +577,7 @@ class Utils {
|
|
|
559
577
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
560
578
|
}
|
|
561
579
|
if (isRequired && schema.default === undefined) {
|
|
580
|
+
parameter.isRequired = true;
|
|
562
581
|
requiredParams.push(parameter);
|
|
563
582
|
}
|
|
564
583
|
else {
|
|
@@ -603,7 +622,7 @@ class Utils {
|
|
|
603
622
|
param.value = schema.default;
|
|
604
623
|
}
|
|
605
624
|
}
|
|
606
|
-
static parseApiInfo(operationItem,
|
|
625
|
+
static parseApiInfo(operationItem, options) {
|
|
607
626
|
var _a, _b;
|
|
608
627
|
const requiredParams = [];
|
|
609
628
|
const optionalParams = [];
|
|
@@ -617,11 +636,12 @@ class Utils {
|
|
|
617
636
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
618
637
|
};
|
|
619
638
|
const schema = param.schema;
|
|
620
|
-
if (allowMultipleParameters && schema) {
|
|
639
|
+
if (options.allowMultipleParameters && schema) {
|
|
621
640
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
622
641
|
}
|
|
623
642
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
624
643
|
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
644
|
+
parameter.isRequired = true;
|
|
625
645
|
requiredParams.push(parameter);
|
|
626
646
|
}
|
|
627
647
|
else {
|
|
@@ -635,7 +655,7 @@ class Utils {
|
|
|
635
655
|
const requestJson = requestBody.content["application/json"];
|
|
636
656
|
if (Object.keys(requestJson).length !== 0) {
|
|
637
657
|
const schema = requestJson.schema;
|
|
638
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
658
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
639
659
|
requiredParams.push(...requiredP);
|
|
640
660
|
optionalParams.push(...optionalP);
|
|
641
661
|
}
|
|
@@ -666,14 +686,13 @@ class Utils {
|
|
|
666
686
|
}
|
|
667
687
|
return [command, warning];
|
|
668
688
|
}
|
|
669
|
-
static listSupportedAPIs(spec,
|
|
689
|
+
static listSupportedAPIs(spec, options) {
|
|
670
690
|
const paths = spec.paths;
|
|
671
691
|
const result = {};
|
|
672
692
|
for (const path in paths) {
|
|
673
693
|
const methods = paths[path];
|
|
674
694
|
for (const method in methods) {
|
|
675
|
-
|
|
676
|
-
if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2, isCopilot)) {
|
|
695
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
677
696
|
const operationObject = methods[method];
|
|
678
697
|
result[`${method.toUpperCase()} ${path}`] = operationObject;
|
|
679
698
|
}
|
|
@@ -681,7 +700,7 @@ class Utils {
|
|
|
681
700
|
}
|
|
682
701
|
return result;
|
|
683
702
|
}
|
|
684
|
-
static validateSpec(spec, parser, isSwaggerFile,
|
|
703
|
+
static validateSpec(spec, parser, isSwaggerFile, options) {
|
|
685
704
|
const errors = [];
|
|
686
705
|
const warnings = [];
|
|
687
706
|
if (isSwaggerFile) {
|
|
@@ -691,7 +710,7 @@ class Utils {
|
|
|
691
710
|
});
|
|
692
711
|
}
|
|
693
712
|
// Server validation
|
|
694
|
-
const serverErrors = Utils.validateServer(spec,
|
|
713
|
+
const serverErrors = Utils.validateServer(spec, options);
|
|
695
714
|
errors.push(...serverErrors);
|
|
696
715
|
// Remote reference not supported
|
|
697
716
|
const refPaths = parser.$refs.paths();
|
|
@@ -704,7 +723,7 @@ class Utils {
|
|
|
704
723
|
});
|
|
705
724
|
}
|
|
706
725
|
// No supported API
|
|
707
|
-
const apiMap = Utils.listSupportedAPIs(spec,
|
|
726
|
+
const apiMap = Utils.listSupportedAPIs(spec, options);
|
|
708
727
|
if (Object.keys(apiMap).length === 0) {
|
|
709
728
|
errors.push({
|
|
710
729
|
type: ErrorType.NoSupportedApi,
|
|
@@ -756,18 +775,31 @@ class Utils {
|
|
|
756
775
|
}
|
|
757
776
|
return safeRegistrationIdEnvName;
|
|
758
777
|
}
|
|
778
|
+
static getAllAPICount(spec) {
|
|
779
|
+
let count = 0;
|
|
780
|
+
const paths = spec.paths;
|
|
781
|
+
for (const path in paths) {
|
|
782
|
+
const methods = paths[path];
|
|
783
|
+
for (const method in methods) {
|
|
784
|
+
if (ConstantString.AllOperationMethods.includes(method)) {
|
|
785
|
+
count++;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return count;
|
|
790
|
+
}
|
|
759
791
|
}
|
|
760
792
|
|
|
761
793
|
// Copyright (c) Microsoft Corporation.
|
|
762
794
|
class SpecFilter {
|
|
763
|
-
static specFilter(filter, unResolveSpec, resolvedSpec,
|
|
795
|
+
static specFilter(filter, unResolveSpec, resolvedSpec, options) {
|
|
764
796
|
try {
|
|
765
797
|
const newSpec = Object.assign({}, unResolveSpec);
|
|
766
798
|
const newPaths = {};
|
|
767
799
|
for (const filterItem of filter) {
|
|
768
800
|
const [method, path] = filterItem.split(" ");
|
|
769
801
|
const methodName = method.toLowerCase();
|
|
770
|
-
if (!Utils.isSupportedApi(methodName, path, resolvedSpec,
|
|
802
|
+
if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
|
|
771
803
|
continue;
|
|
772
804
|
}
|
|
773
805
|
if (!newPaths[path]) {
|
|
@@ -793,7 +825,7 @@ class SpecFilter {
|
|
|
793
825
|
|
|
794
826
|
// Copyright (c) Microsoft Corporation.
|
|
795
827
|
class ManifestUpdater {
|
|
796
|
-
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec) {
|
|
828
|
+
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
|
|
797
829
|
const manifest = await fs.readJSON(manifestPath);
|
|
798
830
|
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
799
831
|
manifest.plugins = [
|
|
@@ -803,7 +835,7 @@ class ManifestUpdater {
|
|
|
803
835
|
];
|
|
804
836
|
ManifestUpdater.updateManifestDescription(manifest, spec);
|
|
805
837
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
806
|
-
const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath);
|
|
838
|
+
const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
|
|
807
839
|
return [manifest, apiPlugin];
|
|
808
840
|
}
|
|
809
841
|
static updateManifestDescription(manifest, spec) {
|
|
@@ -827,7 +859,7 @@ class ManifestUpdater {
|
|
|
827
859
|
}
|
|
828
860
|
return parameter;
|
|
829
861
|
}
|
|
830
|
-
static generatePluginManifestSchema(spec, specRelativePath) {
|
|
862
|
+
static generatePluginManifestSchema(spec, specRelativePath, options) {
|
|
831
863
|
var _a, _b, _c;
|
|
832
864
|
const functions = [];
|
|
833
865
|
const functionNames = [];
|
|
@@ -837,7 +869,7 @@ class ManifestUpdater {
|
|
|
837
869
|
if (pathItem) {
|
|
838
870
|
const operations = pathItem;
|
|
839
871
|
for (const method in operations) {
|
|
840
|
-
if (
|
|
872
|
+
if (options.allowMethods.includes(method)) {
|
|
841
873
|
const operationItem = operations[method];
|
|
842
874
|
if (operationItem) {
|
|
843
875
|
const operationId = operationItem.operationId;
|
|
@@ -910,43 +942,50 @@ class ManifestUpdater {
|
|
|
910
942
|
};
|
|
911
943
|
return apiPlugin;
|
|
912
944
|
}
|
|
913
|
-
static async updateManifest(manifestPath, outputSpecPath,
|
|
945
|
+
static async updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
|
|
914
946
|
try {
|
|
915
947
|
const originalManifest = await fs.readJSON(manifestPath);
|
|
916
948
|
const updatedPart = {};
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
commands
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
949
|
+
updatedPart.composeExtensions = [];
|
|
950
|
+
let warnings = [];
|
|
951
|
+
if (options.projectType === ProjectType.SME) {
|
|
952
|
+
const updateResult = await ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
|
|
953
|
+
const commands = updateResult[0];
|
|
954
|
+
warnings = updateResult[1];
|
|
955
|
+
const composeExtension = {
|
|
956
|
+
composeExtensionType: "apiBased",
|
|
957
|
+
apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
|
|
958
|
+
commands: commands,
|
|
959
|
+
};
|
|
960
|
+
if (authInfo) {
|
|
961
|
+
const auth = authInfo.authScheme;
|
|
962
|
+
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
963
|
+
const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
964
|
+
composeExtension.authorization = {
|
|
965
|
+
authType: "apiSecretServiceAuth",
|
|
966
|
+
apiSecretServiceAuthConfiguration: {
|
|
967
|
+
apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
|
|
968
|
+
},
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
|
|
972
|
+
const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
|
|
973
|
+
composeExtension.authorization = {
|
|
974
|
+
authType: "oAuth2.0",
|
|
975
|
+
oAuthConfiguration: {
|
|
976
|
+
oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
|
|
977
|
+
},
|
|
978
|
+
};
|
|
979
|
+
updatedPart.webApplicationInfo = {
|
|
980
|
+
id: "${{AAD_APP_CLIENT_ID}}",
|
|
981
|
+
resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
|
|
982
|
+
};
|
|
983
|
+
}
|
|
945
984
|
}
|
|
985
|
+
updatedPart.composeExtensions = [composeExtension];
|
|
946
986
|
}
|
|
947
987
|
updatedPart.description = originalManifest.description;
|
|
948
988
|
ManifestUpdater.updateManifestDescription(updatedPart, spec);
|
|
949
|
-
updatedPart.composeExtensions = isMe === undefined || isMe === true ? [composeExtension] : [];
|
|
950
989
|
const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
|
|
951
990
|
return [updatedManifest, warnings];
|
|
952
991
|
}
|
|
@@ -954,7 +993,8 @@ class ManifestUpdater {
|
|
|
954
993
|
throw new SpecParserError(err.toString(), ErrorType.UpdateManifestFailed);
|
|
955
994
|
}
|
|
956
995
|
}
|
|
957
|
-
static async generateCommands(spec,
|
|
996
|
+
static async generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
|
|
997
|
+
var _a;
|
|
958
998
|
const paths = spec.paths;
|
|
959
999
|
const commands = [];
|
|
960
1000
|
const warnings = [];
|
|
@@ -965,14 +1005,16 @@ class ManifestUpdater {
|
|
|
965
1005
|
const operations = pathItem;
|
|
966
1006
|
// Currently only support GET and POST method
|
|
967
1007
|
for (const method in operations) {
|
|
968
|
-
if (
|
|
1008
|
+
if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
|
|
969
1009
|
const operationItem = operations[method];
|
|
970
1010
|
if (operationItem) {
|
|
971
|
-
const [command, warning] = Utils.parseApiInfo(operationItem,
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1011
|
+
const [command, warning] = Utils.parseApiInfo(operationItem, options);
|
|
1012
|
+
if (adaptiveCardFolder) {
|
|
1013
|
+
const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
|
|
1014
|
+
command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
|
|
1015
|
+
? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
|
|
1016
|
+
: "";
|
|
1017
|
+
}
|
|
976
1018
|
if (warning) {
|
|
977
1019
|
warnings.push(warning);
|
|
978
1020
|
}
|
|
@@ -1255,9 +1297,11 @@ class SpecParser {
|
|
|
1255
1297
|
allowMissingId: true,
|
|
1256
1298
|
allowSwagger: true,
|
|
1257
1299
|
allowAPIKeyAuth: false,
|
|
1300
|
+
allowBearerTokenAuth: false,
|
|
1258
1301
|
allowMultipleParameters: false,
|
|
1259
1302
|
allowOauth2: false,
|
|
1260
|
-
|
|
1303
|
+
allowMethods: ["get", "post"],
|
|
1304
|
+
projectType: ProjectType.SME,
|
|
1261
1305
|
};
|
|
1262
1306
|
this.pathOrSpec = pathOrDoc;
|
|
1263
1307
|
this.parser = new SwaggerParser();
|
|
@@ -1290,7 +1334,23 @@ class SpecParser {
|
|
|
1290
1334
|
],
|
|
1291
1335
|
};
|
|
1292
1336
|
}
|
|
1293
|
-
|
|
1337
|
+
if (this.options.projectType === ProjectType.SME ||
|
|
1338
|
+
this.options.projectType === ProjectType.Copilot) {
|
|
1339
|
+
if (this.spec.openapi >= "3.1.0") {
|
|
1340
|
+
return {
|
|
1341
|
+
status: ValidationStatus.Error,
|
|
1342
|
+
warnings: [],
|
|
1343
|
+
errors: [
|
|
1344
|
+
{
|
|
1345
|
+
type: ErrorType.SpecVersionNotSupported,
|
|
1346
|
+
content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
|
|
1347
|
+
data: this.spec.openapi,
|
|
1348
|
+
},
|
|
1349
|
+
],
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
|
|
1294
1354
|
}
|
|
1295
1355
|
catch (err) {
|
|
1296
1356
|
throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
|
|
@@ -1311,7 +1371,11 @@ class SpecParser {
|
|
|
1311
1371
|
await this.loadSpec();
|
|
1312
1372
|
const spec = this.spec;
|
|
1313
1373
|
const apiMap = this.getAllSupportedAPIs(spec);
|
|
1314
|
-
const result =
|
|
1374
|
+
const result = {
|
|
1375
|
+
validAPIs: [],
|
|
1376
|
+
allAPICount: 0,
|
|
1377
|
+
validAPICount: 0,
|
|
1378
|
+
};
|
|
1315
1379
|
for (const apiKey in apiMap) {
|
|
1316
1380
|
const apiResult = {
|
|
1317
1381
|
api: "",
|
|
@@ -1336,13 +1400,15 @@ class SpecParser {
|
|
|
1336
1400
|
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1337
1401
|
for (const auths of authArray) {
|
|
1338
1402
|
if (auths.length === 1) {
|
|
1339
|
-
apiResult.auth = auths[0]
|
|
1403
|
+
apiResult.auth = auths[0];
|
|
1340
1404
|
break;
|
|
1341
1405
|
}
|
|
1342
1406
|
}
|
|
1343
1407
|
apiResult.api = apiKey;
|
|
1344
|
-
result.push(apiResult);
|
|
1408
|
+
result.validAPIs.push(apiResult);
|
|
1345
1409
|
}
|
|
1410
|
+
result.allAPICount = Utils.getAllAPICount(spec);
|
|
1411
|
+
result.validAPICount = result.validAPIs.length;
|
|
1346
1412
|
return result;
|
|
1347
1413
|
}
|
|
1348
1414
|
catch (err) {
|
|
@@ -1365,7 +1431,7 @@ class SpecParser {
|
|
|
1365
1431
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1366
1432
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
1367
1433
|
}
|
|
1368
|
-
const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options
|
|
1434
|
+
const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
|
|
1369
1435
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1370
1436
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
1371
1437
|
}
|
|
@@ -1406,7 +1472,7 @@ class SpecParser {
|
|
|
1406
1472
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1407
1473
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
1408
1474
|
}
|
|
1409
|
-
const [updatedManifest, apiPlugin] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec);
|
|
1475
|
+
const [updatedManifest, apiPlugin] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
|
|
1410
1476
|
await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1411
1477
|
await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
|
|
1412
1478
|
}
|
|
@@ -1424,9 +1490,8 @@ class SpecParser {
|
|
|
1424
1490
|
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1425
1491
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
1426
1492
|
* @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
|
|
1427
|
-
* @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
|
|
1428
1493
|
*/
|
|
1429
|
-
async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal
|
|
1494
|
+
async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
1430
1495
|
const result = {
|
|
1431
1496
|
allSuccess: true,
|
|
1432
1497
|
warnings: [],
|
|
@@ -1435,23 +1500,23 @@ class SpecParser {
|
|
|
1435
1500
|
const newSpecs = await this.getFilteredSpecs(filter, signal);
|
|
1436
1501
|
const newUnResolvedSpec = newSpecs[0];
|
|
1437
1502
|
const newSpec = newSpecs[1];
|
|
1438
|
-
const
|
|
1439
|
-
let
|
|
1503
|
+
const authSet = new Set();
|
|
1504
|
+
let hasMultipleAuth = false;
|
|
1440
1505
|
for (const url in newSpec.paths) {
|
|
1441
1506
|
for (const method in newSpec.paths[url]) {
|
|
1442
1507
|
const operation = newSpec.paths[url][method];
|
|
1443
1508
|
const authArray = Utils.getAuthArray(operation.security, newSpec);
|
|
1444
1509
|
if (authArray && authArray.length > 0) {
|
|
1445
|
-
|
|
1446
|
-
if (
|
|
1447
|
-
|
|
1510
|
+
authSet.add(authArray[0][0]);
|
|
1511
|
+
if (authSet.size > 1) {
|
|
1512
|
+
hasMultipleAuth = true;
|
|
1448
1513
|
break;
|
|
1449
1514
|
}
|
|
1450
1515
|
}
|
|
1451
1516
|
}
|
|
1452
1517
|
}
|
|
1453
|
-
if (
|
|
1454
|
-
throw new SpecParserError(ConstantString.
|
|
1518
|
+
if (hasMultipleAuth && this.options.projectType !== ProjectType.TeamsAi) {
|
|
1519
|
+
throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
|
|
1455
1520
|
}
|
|
1456
1521
|
let resultStr;
|
|
1457
1522
|
if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
|
|
@@ -1461,12 +1526,11 @@ class SpecParser {
|
|
|
1461
1526
|
resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
|
|
1462
1527
|
}
|
|
1463
1528
|
await fs.outputFile(outputSpecPath, resultStr);
|
|
1464
|
-
if (
|
|
1465
|
-
// Only generate adaptive card for Messaging Extension
|
|
1529
|
+
if (adaptiveCardFolder) {
|
|
1466
1530
|
for (const url in newSpec.paths) {
|
|
1467
1531
|
for (const method in newSpec.paths[url]) {
|
|
1468
|
-
// paths object may contain description/summary, so we need to check if it is a operation object
|
|
1469
|
-
if (
|
|
1532
|
+
// paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
|
|
1533
|
+
if (this.options.allowMethods.includes(method)) {
|
|
1470
1534
|
const operation = newSpec.paths[url][method];
|
|
1471
1535
|
try {
|
|
1472
1536
|
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
@@ -1491,8 +1555,8 @@ class SpecParser {
|
|
|
1491
1555
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1492
1556
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
1493
1557
|
}
|
|
1494
|
-
const
|
|
1495
|
-
const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath,
|
|
1558
|
+
const authInfo = Array.from(authSet)[0];
|
|
1559
|
+
const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
|
|
1496
1560
|
await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1497
1561
|
result.warnings.push(...warnings);
|
|
1498
1562
|
}
|
|
@@ -1521,11 +1585,11 @@ class SpecParser {
|
|
|
1521
1585
|
if (this.apiMap !== undefined) {
|
|
1522
1586
|
return this.apiMap;
|
|
1523
1587
|
}
|
|
1524
|
-
const result = Utils.listSupportedAPIs(spec, this.options
|
|
1588
|
+
const result = Utils.listSupportedAPIs(spec, this.options);
|
|
1525
1589
|
this.apiMap = result;
|
|
1526
1590
|
return result;
|
|
1527
1591
|
}
|
|
1528
1592
|
}
|
|
1529
1593
|
|
|
1530
|
-
export { AdaptiveCardGenerator, ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|
|
1594
|
+
export { AdaptiveCardGenerator, ConstantString, ErrorType, ProjectType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|
|
1531
1595
|
//# sourceMappingURL=index.esm2017.mjs.map
|