@microsoft/m365-spec-parser 0.1.1-alpha.78701ec6a.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 +317 -67
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +427 -150
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +321 -67
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +433 -149
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +5 -1
- package/dist/src/index.browser.d.ts +2 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/interfaces.d.ts +47 -18
- package/dist/src/manifestUpdater.d.ts +8 -4
- package/dist/src/specFilter.d.ts +2 -1
- package/dist/src/specParser.browser.d.ts +15 -1
- package/dist/src/specParser.d.ts +15 -2
- package/dist/src/utils.d.ts +20 -16
- package/package.json +4 -4
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";
|
|
@@ -69,6 +70,7 @@ exports.ErrorType = void 0;
|
|
|
69
70
|
ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
|
|
70
71
|
ErrorType["GenerateFailed"] = "generate-failed";
|
|
71
72
|
ErrorType["ValidateFailed"] = "validate-failed";
|
|
73
|
+
ErrorType["GetSpecFailed"] = "get-spec-failed";
|
|
72
74
|
ErrorType["Cancelled"] = "cancelled";
|
|
73
75
|
ErrorType["Unknown"] = "unknown";
|
|
74
76
|
})(exports.ErrorType || (exports.ErrorType = {}));
|
|
@@ -91,7 +93,13 @@ exports.ValidationStatus = void 0;
|
|
|
91
93
|
ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
|
|
92
94
|
ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
|
|
93
95
|
ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
|
|
94
|
-
})(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 = {}));
|
|
95
103
|
|
|
96
104
|
// Copyright (c) Microsoft Corporation.
|
|
97
105
|
class ConstantString {
|
|
@@ -110,7 +118,9 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
|
|
|
110
118
|
ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
|
|
111
119
|
ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
|
|
112
120
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
113
|
-
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.";
|
|
123
|
+
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
114
124
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
115
125
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
116
126
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
@@ -122,6 +132,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
|
122
132
|
ConstantString.TextBlockType = "TextBlock";
|
|
123
133
|
ConstantString.ContainerType = "Container";
|
|
124
134
|
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
135
|
+
ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
|
|
125
136
|
ConstantString.ResponseCodeFor20X = [
|
|
126
137
|
"200",
|
|
127
138
|
"201",
|
|
@@ -181,7 +192,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
|
|
|
181
192
|
ConstantString.CommandDescriptionMaxLens = 128;
|
|
182
193
|
ConstantString.ParameterDescriptionMaxLens = 128;
|
|
183
194
|
ConstantString.CommandTitleMaxLens = 32;
|
|
184
|
-
ConstantString.ParameterTitleMaxLens = 32;
|
|
195
|
+
ConstantString.ParameterTitleMaxLens = 32;
|
|
196
|
+
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
185
197
|
|
|
186
198
|
// Copyright (c) Microsoft Corporation.
|
|
187
199
|
class SpecParserError extends Error {
|
|
@@ -193,7 +205,18 @@ class SpecParserError extends Error {
|
|
|
193
205
|
|
|
194
206
|
// Copyright (c) Microsoft Corporation.
|
|
195
207
|
class Utils {
|
|
196
|
-
static
|
|
208
|
+
static hasNestedObjectInSchema(schema) {
|
|
209
|
+
if (schema.type === "object") {
|
|
210
|
+
for (const property in schema.properties) {
|
|
211
|
+
const nestedSchema = schema.properties[property];
|
|
212
|
+
if (nestedSchema.type === "object") {
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
static checkParameters(paramObject, isCopilot) {
|
|
197
220
|
const paramResult = {
|
|
198
221
|
requiredNum: 0,
|
|
199
222
|
optionalNum: 0,
|
|
@@ -205,7 +228,20 @@ class Utils {
|
|
|
205
228
|
for (let i = 0; i < paramObject.length; i++) {
|
|
206
229
|
const param = paramObject[i];
|
|
207
230
|
const schema = param.schema;
|
|
231
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
232
|
+
paramResult.isValid = false;
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
208
235
|
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
236
|
+
if (isCopilot) {
|
|
237
|
+
if (isRequiredWithoutDefault) {
|
|
238
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
242
|
+
}
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
209
245
|
if (param.in === "header" || param.in === "cookie") {
|
|
210
246
|
if (isRequiredWithoutDefault) {
|
|
211
247
|
paramResult.isValid = false;
|
|
@@ -232,7 +268,7 @@ class Utils {
|
|
|
232
268
|
}
|
|
233
269
|
return paramResult;
|
|
234
270
|
}
|
|
235
|
-
static checkPostBody(schema, isRequired = false) {
|
|
271
|
+
static checkPostBody(schema, isRequired = false, isCopilot = false) {
|
|
236
272
|
var _a;
|
|
237
273
|
const paramResult = {
|
|
238
274
|
requiredNum: 0,
|
|
@@ -243,6 +279,10 @@ class Utils {
|
|
|
243
279
|
return paramResult;
|
|
244
280
|
}
|
|
245
281
|
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
282
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
283
|
+
paramResult.isValid = false;
|
|
284
|
+
return paramResult;
|
|
285
|
+
}
|
|
246
286
|
if (schema.type === "string" ||
|
|
247
287
|
schema.type === "integer" ||
|
|
248
288
|
schema.type === "boolean" ||
|
|
@@ -261,19 +301,22 @@ class Utils {
|
|
|
261
301
|
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
262
302
|
isRequired = true;
|
|
263
303
|
}
|
|
264
|
-
const result = Utils.checkPostBody(properties[property], isRequired);
|
|
304
|
+
const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
|
|
265
305
|
paramResult.requiredNum += result.requiredNum;
|
|
266
306
|
paramResult.optionalNum += result.optionalNum;
|
|
267
307
|
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
268
308
|
}
|
|
269
309
|
}
|
|
270
310
|
else {
|
|
271
|
-
if (isRequiredWithoutDefault) {
|
|
311
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
272
312
|
paramResult.isValid = false;
|
|
273
313
|
}
|
|
274
314
|
}
|
|
275
315
|
return paramResult;
|
|
276
316
|
}
|
|
317
|
+
static containMultipleMediaTypes(bodyObject) {
|
|
318
|
+
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
319
|
+
}
|
|
277
320
|
/**
|
|
278
321
|
* Checks if the given API is supported.
|
|
279
322
|
* @param {string} method - The HTTP method of the API.
|
|
@@ -288,32 +331,40 @@ class Utils {
|
|
|
288
331
|
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
289
332
|
* 6. only support request body with “application/json” content type
|
|
290
333
|
*/
|
|
291
|
-
static isSupportedApi(method, path, spec,
|
|
334
|
+
static isSupportedApi(method, path, spec, options) {
|
|
335
|
+
var _a;
|
|
292
336
|
const pathObj = spec.paths[path];
|
|
293
337
|
method = method.toLocaleLowerCase();
|
|
294
338
|
if (pathObj) {
|
|
295
|
-
if ((
|
|
296
|
-
pathObj[method]) {
|
|
339
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
|
|
297
340
|
const securities = pathObj[method].security;
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
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
|
+
}
|
|
301
349
|
}
|
|
302
350
|
const operationObject = pathObj[method];
|
|
303
|
-
if (!allowMissingId && !operationObject.operationId) {
|
|
351
|
+
if (!options.allowMissingId && !operationObject.operationId) {
|
|
304
352
|
return false;
|
|
305
353
|
}
|
|
306
354
|
const paramObject = operationObject.parameters;
|
|
307
355
|
const requestBody = operationObject.requestBody;
|
|
308
356
|
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
309
|
-
|
|
310
|
-
if (mediaTypesCount > 1) {
|
|
357
|
+
if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
|
|
311
358
|
return false;
|
|
312
359
|
}
|
|
313
|
-
const responseJson = Utils.getResponseJson(operationObject);
|
|
360
|
+
const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
|
|
314
361
|
if (Object.keys(responseJson).length === 0) {
|
|
315
362
|
return false;
|
|
316
363
|
}
|
|
364
|
+
// Teams AI project doesn't care about request parameters/body
|
|
365
|
+
if (isTeamsAi) {
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
317
368
|
let requestBodyParamResult = {
|
|
318
369
|
requiredNum: 0,
|
|
319
370
|
optionalNum: 0,
|
|
@@ -321,18 +372,26 @@ class Utils {
|
|
|
321
372
|
};
|
|
322
373
|
if (requestJsonBody) {
|
|
323
374
|
const requestBodySchema = requestJsonBody.schema;
|
|
324
|
-
|
|
375
|
+
if (isCopilot && requestBodySchema.type !== "object") {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
|
|
325
379
|
}
|
|
326
380
|
if (!requestBodyParamResult.isValid) {
|
|
327
381
|
return false;
|
|
328
382
|
}
|
|
329
|
-
const paramResult = Utils.checkParameters(paramObject);
|
|
383
|
+
const paramResult = Utils.checkParameters(paramObject, isCopilot);
|
|
330
384
|
if (!paramResult.isValid) {
|
|
331
385
|
return false;
|
|
332
386
|
}
|
|
387
|
+
// Copilot support arbitrary parameters
|
|
388
|
+
if (isCopilot) {
|
|
389
|
+
return true;
|
|
390
|
+
}
|
|
333
391
|
if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
|
|
334
|
-
if (allowMultipleParameters &&
|
|
335
|
-
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
392
|
+
if (options.allowMultipleParameters &&
|
|
393
|
+
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
394
|
+
ConstantString.SMERequiredParamsMaxNum) {
|
|
336
395
|
return true;
|
|
337
396
|
}
|
|
338
397
|
return false;
|
|
@@ -351,29 +410,20 @@ class Utils {
|
|
|
351
410
|
}
|
|
352
411
|
return false;
|
|
353
412
|
}
|
|
354
|
-
static isSupportedAuth(
|
|
355
|
-
if (
|
|
413
|
+
static isSupportedAuth(authSchemeArray, options) {
|
|
414
|
+
if (authSchemeArray.length === 0) {
|
|
356
415
|
return true;
|
|
357
416
|
}
|
|
358
|
-
if (allowAPIKeyAuth || allowOauth2) {
|
|
417
|
+
if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
|
|
359
418
|
// Currently we don't support multiple auth in one operation
|
|
360
|
-
if (
|
|
419
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
361
420
|
return false;
|
|
362
421
|
}
|
|
363
|
-
for (const auths of
|
|
422
|
+
for (const auths of authSchemeArray) {
|
|
364
423
|
if (auths.length === 1) {
|
|
365
|
-
if (
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
else if (!allowAPIKeyAuth &&
|
|
369
|
-
allowOauth2 &&
|
|
370
|
-
Utils.isBearerTokenAuth(auths[0].authSchema)) {
|
|
371
|
-
return true;
|
|
372
|
-
}
|
|
373
|
-
else if (allowAPIKeyAuth &&
|
|
374
|
-
allowOauth2 &&
|
|
375
|
-
(Utils.isAPIKeyAuth(auths[0].authSchema) ||
|
|
376
|
-
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))) {
|
|
377
427
|
return true;
|
|
378
428
|
}
|
|
379
429
|
}
|
|
@@ -381,13 +431,17 @@ class Utils {
|
|
|
381
431
|
}
|
|
382
432
|
return false;
|
|
383
433
|
}
|
|
384
|
-
static
|
|
385
|
-
return
|
|
434
|
+
static isBearerTokenAuth(authScheme) {
|
|
435
|
+
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
436
|
+
}
|
|
437
|
+
static isAPIKeyAuth(authScheme) {
|
|
438
|
+
return authScheme.type === "apiKey";
|
|
386
439
|
}
|
|
387
|
-
static
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
440
|
+
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
441
|
+
if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
return false;
|
|
391
445
|
}
|
|
392
446
|
static getAuthArray(securities, spec) {
|
|
393
447
|
var _a;
|
|
@@ -400,7 +454,7 @@ class Utils {
|
|
|
400
454
|
for (const name in security) {
|
|
401
455
|
const auth = securitySchemas[name];
|
|
402
456
|
authArray.push({
|
|
403
|
-
|
|
457
|
+
authScheme: auth,
|
|
404
458
|
name: name,
|
|
405
459
|
});
|
|
406
460
|
}
|
|
@@ -415,18 +469,19 @@ class Utils {
|
|
|
415
469
|
static updateFirstLetter(str) {
|
|
416
470
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
417
471
|
}
|
|
418
|
-
static getResponseJson(operationObject) {
|
|
472
|
+
static getResponseJson(operationObject, isTeamsAiProject = false) {
|
|
419
473
|
var _a, _b;
|
|
420
474
|
let json = {};
|
|
421
475
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
422
476
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
423
|
-
const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
|
|
424
|
-
if (mediaTypesCount > 1) {
|
|
425
|
-
return {};
|
|
426
|
-
}
|
|
427
477
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
428
478
|
json = responseObject.content["application/json"];
|
|
429
|
-
|
|
479
|
+
if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
|
|
480
|
+
json = {};
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
430
485
|
}
|
|
431
486
|
}
|
|
432
487
|
return json;
|
|
@@ -500,7 +555,7 @@ class Utils {
|
|
|
500
555
|
}
|
|
501
556
|
return errors;
|
|
502
557
|
}
|
|
503
|
-
static validateServer(spec,
|
|
558
|
+
static validateServer(spec, options) {
|
|
504
559
|
const errors = [];
|
|
505
560
|
let hasTopLevelServers = false;
|
|
506
561
|
let hasPathLevelServers = false;
|
|
@@ -521,7 +576,7 @@ class Utils {
|
|
|
521
576
|
}
|
|
522
577
|
for (const method in methods) {
|
|
523
578
|
const operationObject = methods[method];
|
|
524
|
-
if (Utils.isSupportedApi(method, path, spec,
|
|
579
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
525
580
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
526
581
|
hasOperationLevelServers = true;
|
|
527
582
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -564,6 +619,7 @@ class Utils {
|
|
|
564
619
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
565
620
|
}
|
|
566
621
|
if (isRequired && schema.default === undefined) {
|
|
622
|
+
parameter.isRequired = true;
|
|
567
623
|
requiredParams.push(parameter);
|
|
568
624
|
}
|
|
569
625
|
else {
|
|
@@ -608,7 +664,7 @@ class Utils {
|
|
|
608
664
|
param.value = schema.default;
|
|
609
665
|
}
|
|
610
666
|
}
|
|
611
|
-
static parseApiInfo(operationItem,
|
|
667
|
+
static parseApiInfo(operationItem, options) {
|
|
612
668
|
var _a, _b;
|
|
613
669
|
const requiredParams = [];
|
|
614
670
|
const optionalParams = [];
|
|
@@ -622,11 +678,12 @@ class Utils {
|
|
|
622
678
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
623
679
|
};
|
|
624
680
|
const schema = param.schema;
|
|
625
|
-
if (allowMultipleParameters && schema) {
|
|
681
|
+
if (options.allowMultipleParameters && schema) {
|
|
626
682
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
627
683
|
}
|
|
628
684
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
629
685
|
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
686
|
+
parameter.isRequired = true;
|
|
630
687
|
requiredParams.push(parameter);
|
|
631
688
|
}
|
|
632
689
|
else {
|
|
@@ -640,7 +697,7 @@ class Utils {
|
|
|
640
697
|
const requestJson = requestBody.content["application/json"];
|
|
641
698
|
if (Object.keys(requestJson).length !== 0) {
|
|
642
699
|
const schema = requestJson.schema;
|
|
643
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
700
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
644
701
|
requiredParams.push(...requiredP);
|
|
645
702
|
optionalParams.push(...optionalP);
|
|
646
703
|
}
|
|
@@ -671,14 +728,13 @@ class Utils {
|
|
|
671
728
|
}
|
|
672
729
|
return [command, warning];
|
|
673
730
|
}
|
|
674
|
-
static listSupportedAPIs(spec,
|
|
731
|
+
static listSupportedAPIs(spec, options) {
|
|
675
732
|
const paths = spec.paths;
|
|
676
733
|
const result = {};
|
|
677
734
|
for (const path in paths) {
|
|
678
735
|
const methods = paths[path];
|
|
679
736
|
for (const method in methods) {
|
|
680
|
-
|
|
681
|
-
if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
|
|
737
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
682
738
|
const operationObject = methods[method];
|
|
683
739
|
result[`${method.toUpperCase()} ${path}`] = operationObject;
|
|
684
740
|
}
|
|
@@ -686,7 +742,7 @@ class Utils {
|
|
|
686
742
|
}
|
|
687
743
|
return result;
|
|
688
744
|
}
|
|
689
|
-
static validateSpec(spec, parser, isSwaggerFile,
|
|
745
|
+
static validateSpec(spec, parser, isSwaggerFile, options) {
|
|
690
746
|
const errors = [];
|
|
691
747
|
const warnings = [];
|
|
692
748
|
if (isSwaggerFile) {
|
|
@@ -696,7 +752,7 @@ class Utils {
|
|
|
696
752
|
});
|
|
697
753
|
}
|
|
698
754
|
// Server validation
|
|
699
|
-
const serverErrors = Utils.validateServer(spec,
|
|
755
|
+
const serverErrors = Utils.validateServer(spec, options);
|
|
700
756
|
errors.push(...serverErrors);
|
|
701
757
|
// Remote reference not supported
|
|
702
758
|
const refPaths = parser.$refs.paths();
|
|
@@ -709,7 +765,7 @@ class Utils {
|
|
|
709
765
|
});
|
|
710
766
|
}
|
|
711
767
|
// No supported API
|
|
712
|
-
const apiMap = Utils.listSupportedAPIs(spec,
|
|
768
|
+
const apiMap = Utils.listSupportedAPIs(spec, options);
|
|
713
769
|
if (Object.keys(apiMap).length === 0) {
|
|
714
770
|
errors.push({
|
|
715
771
|
type: exports.ErrorType.NoSupportedApi,
|
|
@@ -761,18 +817,31 @@ class Utils {
|
|
|
761
817
|
}
|
|
762
818
|
return safeRegistrationIdEnvName;
|
|
763
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
|
+
}
|
|
764
833
|
}
|
|
765
834
|
|
|
766
835
|
// Copyright (c) Microsoft Corporation.
|
|
767
836
|
class SpecFilter {
|
|
768
|
-
static specFilter(filter, unResolveSpec, resolvedSpec,
|
|
837
|
+
static specFilter(filter, unResolveSpec, resolvedSpec, options) {
|
|
769
838
|
try {
|
|
770
839
|
const newSpec = Object.assign({}, unResolveSpec);
|
|
771
840
|
const newPaths = {};
|
|
772
841
|
for (const filterItem of filter) {
|
|
773
842
|
const [method, path] = filterItem.split(" ");
|
|
774
843
|
const methodName = method.toLowerCase();
|
|
775
|
-
if (!Utils.isSupportedApi(methodName, path, resolvedSpec,
|
|
844
|
+
if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
|
|
776
845
|
continue;
|
|
777
846
|
}
|
|
778
847
|
if (!newPaths[path]) {
|
|
@@ -798,47 +867,170 @@ class SpecFilter {
|
|
|
798
867
|
|
|
799
868
|
// Copyright (c) Microsoft Corporation.
|
|
800
869
|
class ManifestUpdater {
|
|
801
|
-
static
|
|
870
|
+
static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
|
|
871
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
872
|
+
const manifest = yield fs__default['default'].readJSON(manifestPath);
|
|
873
|
+
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
874
|
+
manifest.plugins = [
|
|
875
|
+
{
|
|
876
|
+
pluginFile: apiPluginRelativePath,
|
|
877
|
+
},
|
|
878
|
+
];
|
|
879
|
+
ManifestUpdater.updateManifestDescription(manifest, spec);
|
|
880
|
+
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
881
|
+
const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
|
|
882
|
+
return [manifest, apiPlugin];
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
static updateManifestDescription(manifest, spec) {
|
|
802
886
|
var _a, _b;
|
|
887
|
+
manifest.description = {
|
|
888
|
+
short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
|
|
889
|
+
full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : manifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
|
|
893
|
+
let parameter;
|
|
894
|
+
if (schema.type === "string" ||
|
|
895
|
+
schema.type === "boolean" ||
|
|
896
|
+
schema.type === "integer" ||
|
|
897
|
+
schema.type === "number" ||
|
|
898
|
+
schema.type === "array") {
|
|
899
|
+
parameter = schema;
|
|
900
|
+
}
|
|
901
|
+
else {
|
|
902
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), exports.ErrorType.UpdateManifestFailed);
|
|
903
|
+
}
|
|
904
|
+
return parameter;
|
|
905
|
+
}
|
|
906
|
+
static generatePluginManifestSchema(spec, specRelativePath, options) {
|
|
907
|
+
var _a, _b, _c;
|
|
908
|
+
const functions = [];
|
|
909
|
+
const functionNames = [];
|
|
910
|
+
const paths = spec.paths;
|
|
911
|
+
for (const pathUrl in paths) {
|
|
912
|
+
const pathItem = paths[pathUrl];
|
|
913
|
+
if (pathItem) {
|
|
914
|
+
const operations = pathItem;
|
|
915
|
+
for (const method in operations) {
|
|
916
|
+
if (options.allowMethods.includes(method)) {
|
|
917
|
+
const operationItem = operations[method];
|
|
918
|
+
if (operationItem) {
|
|
919
|
+
const operationId = operationItem.operationId;
|
|
920
|
+
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
921
|
+
const paramObject = operationItem.parameters;
|
|
922
|
+
const requestBody = operationItem.requestBody;
|
|
923
|
+
const parameters = {
|
|
924
|
+
type: "object",
|
|
925
|
+
properties: {},
|
|
926
|
+
required: [],
|
|
927
|
+
};
|
|
928
|
+
if (paramObject) {
|
|
929
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
930
|
+
const param = paramObject[i];
|
|
931
|
+
const schema = param.schema;
|
|
932
|
+
parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
|
|
933
|
+
if (param.required) {
|
|
934
|
+
parameters.required.push(param.name);
|
|
935
|
+
}
|
|
936
|
+
if (!parameters.properties[param.name].description) {
|
|
937
|
+
parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
if (requestBody) {
|
|
942
|
+
const requestJsonBody = requestBody.content["application/json"];
|
|
943
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
944
|
+
if (requestBodySchema.type === "object") {
|
|
945
|
+
if (requestBodySchema.required) {
|
|
946
|
+
parameters.required.push(...requestBodySchema.required);
|
|
947
|
+
}
|
|
948
|
+
for (const property in requestBodySchema.properties) {
|
|
949
|
+
const schema = requestBodySchema.properties[property];
|
|
950
|
+
parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
const funcObj = {
|
|
958
|
+
name: operationId,
|
|
959
|
+
description: description,
|
|
960
|
+
parameters: parameters,
|
|
961
|
+
};
|
|
962
|
+
functions.push(funcObj);
|
|
963
|
+
functionNames.push(operationId);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
const apiPlugin = {
|
|
970
|
+
schema_version: "v2",
|
|
971
|
+
name_for_human: spec.info.title,
|
|
972
|
+
description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
|
|
973
|
+
functions: functions,
|
|
974
|
+
runtimes: [
|
|
975
|
+
{
|
|
976
|
+
type: "OpenApi",
|
|
977
|
+
auth: {
|
|
978
|
+
type: "none", // TODO, support auth in the future
|
|
979
|
+
},
|
|
980
|
+
spec: {
|
|
981
|
+
url: specRelativePath,
|
|
982
|
+
},
|
|
983
|
+
run_for_functions: functionNames,
|
|
984
|
+
},
|
|
985
|
+
],
|
|
986
|
+
};
|
|
987
|
+
return apiPlugin;
|
|
988
|
+
}
|
|
989
|
+
static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
|
|
803
990
|
return __awaiter(this, void 0, void 0, function* () {
|
|
804
991
|
try {
|
|
805
992
|
const originalManifest = yield fs__default['default'].readJSON(manifestPath);
|
|
806
993
|
const updatedPart = {};
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
commands
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
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
|
+
}
|
|
835
1029
|
}
|
|
1030
|
+
updatedPart.composeExtensions = [composeExtension];
|
|
836
1031
|
}
|
|
837
|
-
updatedPart.description =
|
|
838
|
-
|
|
839
|
-
full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : originalManifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
|
|
840
|
-
};
|
|
841
|
-
updatedPart.composeExtensions = [composeExtension];
|
|
1032
|
+
updatedPart.description = originalManifest.description;
|
|
1033
|
+
ManifestUpdater.updateManifestDescription(updatedPart, spec);
|
|
842
1034
|
const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
|
|
843
1035
|
return [updatedManifest, warnings];
|
|
844
1036
|
}
|
|
@@ -847,7 +1039,8 @@ class ManifestUpdater {
|
|
|
847
1039
|
}
|
|
848
1040
|
});
|
|
849
1041
|
}
|
|
850
|
-
static generateCommands(spec,
|
|
1042
|
+
static generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
|
|
1043
|
+
var _a;
|
|
851
1044
|
return __awaiter(this, void 0, void 0, function* () {
|
|
852
1045
|
const paths = spec.paths;
|
|
853
1046
|
const commands = [];
|
|
@@ -859,14 +1052,16 @@ class ManifestUpdater {
|
|
|
859
1052
|
const operations = pathItem;
|
|
860
1053
|
// Currently only support GET and POST method
|
|
861
1054
|
for (const method in operations) {
|
|
862
|
-
if (
|
|
1055
|
+
if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
|
|
863
1056
|
const operationItem = operations[method];
|
|
864
1057
|
if (operationItem) {
|
|
865
|
-
const [command, warning] = Utils.parseApiInfo(operationItem,
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
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
|
+
}
|
|
870
1065
|
if (warning) {
|
|
871
1066
|
warnings.push(warning);
|
|
872
1067
|
}
|
|
@@ -1150,8 +1345,11 @@ class SpecParser {
|
|
|
1150
1345
|
allowMissingId: true,
|
|
1151
1346
|
allowSwagger: true,
|
|
1152
1347
|
allowAPIKeyAuth: false,
|
|
1348
|
+
allowBearerTokenAuth: false,
|
|
1153
1349
|
allowMultipleParameters: false,
|
|
1154
1350
|
allowOauth2: false,
|
|
1351
|
+
allowMethods: ["get", "post"],
|
|
1352
|
+
projectType: exports.ProjectType.SME,
|
|
1155
1353
|
};
|
|
1156
1354
|
this.pathOrSpec = pathOrDoc;
|
|
1157
1355
|
this.parser = new SwaggerParser__default['default']();
|
|
@@ -1185,7 +1383,23 @@ class SpecParser {
|
|
|
1185
1383
|
],
|
|
1186
1384
|
};
|
|
1187
1385
|
}
|
|
1188
|
-
|
|
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);
|
|
1189
1403
|
}
|
|
1190
1404
|
catch (err) {
|
|
1191
1405
|
throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
|
|
@@ -1210,7 +1424,11 @@ class SpecParser {
|
|
|
1210
1424
|
yield this.loadSpec();
|
|
1211
1425
|
const spec = this.spec;
|
|
1212
1426
|
const apiMap = this.getAllSupportedAPIs(spec);
|
|
1213
|
-
const result =
|
|
1427
|
+
const result = {
|
|
1428
|
+
validAPIs: [],
|
|
1429
|
+
allAPICount: 0,
|
|
1430
|
+
validAPICount: 0,
|
|
1431
|
+
};
|
|
1214
1432
|
for (const apiKey in apiMap) {
|
|
1215
1433
|
const apiResult = {
|
|
1216
1434
|
api: "",
|
|
@@ -1235,13 +1453,15 @@ class SpecParser {
|
|
|
1235
1453
|
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1236
1454
|
for (const auths of authArray) {
|
|
1237
1455
|
if (auths.length === 1) {
|
|
1238
|
-
apiResult.auth = auths[0]
|
|
1456
|
+
apiResult.auth = auths[0];
|
|
1239
1457
|
break;
|
|
1240
1458
|
}
|
|
1241
1459
|
}
|
|
1242
1460
|
apiResult.api = apiKey;
|
|
1243
|
-
result.push(apiResult);
|
|
1461
|
+
result.validAPIs.push(apiResult);
|
|
1244
1462
|
}
|
|
1463
|
+
result.allAPICount = Utils.getAllAPICount(spec);
|
|
1464
|
+
result.validAPICount = result.validAPIs.length;
|
|
1245
1465
|
return result;
|
|
1246
1466
|
}
|
|
1247
1467
|
catch (err) {
|
|
@@ -1252,49 +1472,110 @@ class SpecParser {
|
|
|
1252
1472
|
}
|
|
1253
1473
|
});
|
|
1254
1474
|
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Generate specs according to the filters.
|
|
1477
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1478
|
+
*/
|
|
1479
|
+
getFilteredSpecs(filter, signal) {
|
|
1480
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1481
|
+
try {
|
|
1482
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1483
|
+
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1484
|
+
}
|
|
1485
|
+
yield this.loadSpec();
|
|
1486
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1487
|
+
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1488
|
+
}
|
|
1489
|
+
const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
|
|
1490
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1491
|
+
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1492
|
+
}
|
|
1493
|
+
const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
|
|
1494
|
+
return [newUnResolvedSpec, newSpec];
|
|
1495
|
+
}
|
|
1496
|
+
catch (err) {
|
|
1497
|
+
if (err instanceof SpecParserError) {
|
|
1498
|
+
throw err;
|
|
1499
|
+
}
|
|
1500
|
+
throw new SpecParserError(err.toString(), exports.ErrorType.GetSpecFailed);
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1255
1504
|
/**
|
|
1256
1505
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
1257
1506
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
1258
1507
|
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1259
1508
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
1260
|
-
* @param
|
|
1509
|
+
* @param pluginFilePath File path of the api plugin file to generate.
|
|
1261
1510
|
*/
|
|
1262
|
-
|
|
1511
|
+
generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
1263
1512
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1264
1513
|
const result = {
|
|
1265
1514
|
allSuccess: true,
|
|
1266
1515
|
warnings: [],
|
|
1267
1516
|
};
|
|
1268
1517
|
try {
|
|
1269
|
-
|
|
1270
|
-
|
|
1518
|
+
const newSpecs = yield this.getFilteredSpecs(filter, signal);
|
|
1519
|
+
const newUnResolvedSpec = newSpecs[0];
|
|
1520
|
+
const newSpec = newSpecs[1];
|
|
1521
|
+
let resultStr;
|
|
1522
|
+
if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
|
|
1523
|
+
resultStr = jsyaml__default['default'].dump(newUnResolvedSpec);
|
|
1271
1524
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1525
|
+
else {
|
|
1526
|
+
resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
|
|
1275
1527
|
}
|
|
1276
|
-
|
|
1528
|
+
yield fs__default['default'].outputFile(outputSpecPath, resultStr);
|
|
1277
1529
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1278
1530
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1279
1531
|
}
|
|
1280
|
-
const
|
|
1281
|
-
|
|
1282
|
-
|
|
1532
|
+
const [updatedManifest, apiPlugin] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
|
|
1533
|
+
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1534
|
+
yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
|
|
1535
|
+
}
|
|
1536
|
+
catch (err) {
|
|
1537
|
+
if (err instanceof SpecParserError) {
|
|
1538
|
+
throw err;
|
|
1539
|
+
}
|
|
1540
|
+
throw new SpecParserError(err.toString(), exports.ErrorType.GenerateFailed);
|
|
1541
|
+
}
|
|
1542
|
+
return result;
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
/**
|
|
1546
|
+
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
1547
|
+
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
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.
|
|
1549
|
+
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
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.
|
|
1551
|
+
*/
|
|
1552
|
+
generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
1553
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1554
|
+
const result = {
|
|
1555
|
+
allSuccess: true,
|
|
1556
|
+
warnings: [],
|
|
1557
|
+
};
|
|
1558
|
+
try {
|
|
1559
|
+
const newSpecs = yield this.getFilteredSpecs(filter, signal);
|
|
1560
|
+
const newUnResolvedSpec = newSpecs[0];
|
|
1561
|
+
const newSpec = newSpecs[1];
|
|
1562
|
+
const authSet = new Set();
|
|
1563
|
+
let hasMultipleAuth = false;
|
|
1283
1564
|
for (const url in newSpec.paths) {
|
|
1284
1565
|
for (const method in newSpec.paths[url]) {
|
|
1285
1566
|
const operation = newSpec.paths[url][method];
|
|
1286
1567
|
const authArray = Utils.getAuthArray(operation.security, newSpec);
|
|
1287
1568
|
if (authArray && authArray.length > 0) {
|
|
1288
|
-
|
|
1289
|
-
if (
|
|
1290
|
-
|
|
1569
|
+
authSet.add(authArray[0][0]);
|
|
1570
|
+
if (authSet.size > 1) {
|
|
1571
|
+
hasMultipleAuth = true;
|
|
1291
1572
|
break;
|
|
1292
1573
|
}
|
|
1293
1574
|
}
|
|
1294
1575
|
}
|
|
1295
1576
|
}
|
|
1296
|
-
if (
|
|
1297
|
-
throw new SpecParserError(ConstantString.
|
|
1577
|
+
if (hasMultipleAuth && this.options.projectType !== exports.ProjectType.TeamsAi) {
|
|
1578
|
+
throw new SpecParserError(ConstantString.MultipleAuthNotSupported, exports.ErrorType.MultipleAuthNotSupported);
|
|
1298
1579
|
}
|
|
1299
1580
|
let resultStr;
|
|
1300
1581
|
if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
|
|
@@ -1304,26 +1585,28 @@ class SpecParser {
|
|
|
1304
1585
|
resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
|
|
1305
1586
|
}
|
|
1306
1587
|
yield fs__default['default'].outputFile(outputSpecPath, resultStr);
|
|
1307
|
-
|
|
1308
|
-
for (const
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1588
|
+
if (adaptiveCardFolder) {
|
|
1589
|
+
for (const url in newSpec.paths) {
|
|
1590
|
+
for (const method in newSpec.paths[url]) {
|
|
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)) {
|
|
1593
|
+
const operation = newSpec.paths[url][method];
|
|
1594
|
+
try {
|
|
1595
|
+
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
1596
|
+
const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
|
|
1597
|
+
const wrappedCard = wrapAdaptiveCard(card, jsonPath);
|
|
1598
|
+
yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
|
|
1599
|
+
const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
|
|
1600
|
+
yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
|
|
1601
|
+
}
|
|
1602
|
+
catch (err) {
|
|
1603
|
+
result.allSuccess = false;
|
|
1604
|
+
result.warnings.push({
|
|
1605
|
+
type: exports.WarningType.GenerateCardFailed,
|
|
1606
|
+
content: err.toString(),
|
|
1607
|
+
data: operation.operationId,
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1327
1610
|
}
|
|
1328
1611
|
}
|
|
1329
1612
|
}
|
|
@@ -1331,8 +1614,8 @@ class SpecParser {
|
|
|
1331
1614
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1332
1615
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1333
1616
|
}
|
|
1334
|
-
const
|
|
1335
|
-
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);
|
|
1336
1619
|
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1337
1620
|
result.warnings.push(...warnings);
|
|
1338
1621
|
}
|
|
@@ -1364,12 +1647,13 @@ class SpecParser {
|
|
|
1364
1647
|
if (this.apiMap !== undefined) {
|
|
1365
1648
|
return this.apiMap;
|
|
1366
1649
|
}
|
|
1367
|
-
const result = Utils.listSupportedAPIs(spec, this.options
|
|
1650
|
+
const result = Utils.listSupportedAPIs(spec, this.options);
|
|
1368
1651
|
this.apiMap = result;
|
|
1369
1652
|
return result;
|
|
1370
1653
|
}
|
|
1371
1654
|
}
|
|
1372
1655
|
|
|
1656
|
+
exports.AdaptiveCardGenerator = AdaptiveCardGenerator;
|
|
1373
1657
|
exports.ConstantString = ConstantString;
|
|
1374
1658
|
exports.SpecParser = SpecParser;
|
|
1375
1659
|
exports.SpecParserError = SpecParserError;
|