@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.esm5.js
CHANGED
|
@@ -45,7 +45,8 @@ var ErrorType;
|
|
|
45
45
|
ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
|
|
46
46
|
ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
|
|
47
47
|
ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
|
|
48
|
-
ErrorType["
|
|
48
|
+
ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
|
|
49
|
+
ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
|
|
49
50
|
ErrorType["ListFailed"] = "list-failed";
|
|
50
51
|
ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
|
|
51
52
|
ErrorType["FilterSpecFailed"] = "filter-spec-failed";
|
|
@@ -53,6 +54,7 @@ var ErrorType;
|
|
|
53
54
|
ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
|
|
54
55
|
ErrorType["GenerateFailed"] = "generate-failed";
|
|
55
56
|
ErrorType["ValidateFailed"] = "validate-failed";
|
|
57
|
+
ErrorType["GetSpecFailed"] = "get-spec-failed";
|
|
56
58
|
ErrorType["Cancelled"] = "cancelled";
|
|
57
59
|
ErrorType["Unknown"] = "unknown";
|
|
58
60
|
})(ErrorType || (ErrorType = {}));
|
|
@@ -75,7 +77,13 @@ var ValidationStatus;
|
|
|
75
77
|
ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
|
|
76
78
|
ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
|
|
77
79
|
ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
|
|
78
|
-
})(ValidationStatus || (ValidationStatus = {}));
|
|
80
|
+
})(ValidationStatus || (ValidationStatus = {}));
|
|
81
|
+
var ProjectType;
|
|
82
|
+
(function (ProjectType) {
|
|
83
|
+
ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
|
|
84
|
+
ProjectType[ProjectType["SME"] = 1] = "SME";
|
|
85
|
+
ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
|
|
86
|
+
})(ProjectType || (ProjectType = {}));
|
|
79
87
|
|
|
80
88
|
// Copyright (c) Microsoft Corporation.
|
|
81
89
|
class SpecParserError extends Error {
|
|
@@ -102,7 +110,9 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
|
|
|
102
110
|
ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
|
|
103
111
|
ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
|
|
104
112
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
105
|
-
ConstantString.
|
|
113
|
+
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
114
|
+
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
115
|
+
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
106
116
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
107
117
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
108
118
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
@@ -114,6 +124,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
|
114
124
|
ConstantString.TextBlockType = "TextBlock";
|
|
115
125
|
ConstantString.ContainerType = "Container";
|
|
116
126
|
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
127
|
+
ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
|
|
117
128
|
ConstantString.ResponseCodeFor20X = [
|
|
118
129
|
"200",
|
|
119
130
|
"201",
|
|
@@ -173,11 +184,23 @@ ConstantString.FullDescriptionMaxLens = 4000;
|
|
|
173
184
|
ConstantString.CommandDescriptionMaxLens = 128;
|
|
174
185
|
ConstantString.ParameterDescriptionMaxLens = 128;
|
|
175
186
|
ConstantString.CommandTitleMaxLens = 32;
|
|
176
|
-
ConstantString.ParameterTitleMaxLens = 32;
|
|
187
|
+
ConstantString.ParameterTitleMaxLens = 32;
|
|
188
|
+
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
177
189
|
|
|
178
190
|
// Copyright (c) Microsoft Corporation.
|
|
179
191
|
class Utils {
|
|
180
|
-
static
|
|
192
|
+
static hasNestedObjectInSchema(schema) {
|
|
193
|
+
if (schema.type === "object") {
|
|
194
|
+
for (const property in schema.properties) {
|
|
195
|
+
const nestedSchema = schema.properties[property];
|
|
196
|
+
if (nestedSchema.type === "object") {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
static checkParameters(paramObject, isCopilot) {
|
|
181
204
|
const paramResult = {
|
|
182
205
|
requiredNum: 0,
|
|
183
206
|
optionalNum: 0,
|
|
@@ -189,7 +212,20 @@ class Utils {
|
|
|
189
212
|
for (let i = 0; i < paramObject.length; i++) {
|
|
190
213
|
const param = paramObject[i];
|
|
191
214
|
const schema = param.schema;
|
|
215
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
216
|
+
paramResult.isValid = false;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
192
219
|
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
220
|
+
if (isCopilot) {
|
|
221
|
+
if (isRequiredWithoutDefault) {
|
|
222
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
226
|
+
}
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
193
229
|
if (param.in === "header" || param.in === "cookie") {
|
|
194
230
|
if (isRequiredWithoutDefault) {
|
|
195
231
|
paramResult.isValid = false;
|
|
@@ -216,7 +252,7 @@ class Utils {
|
|
|
216
252
|
}
|
|
217
253
|
return paramResult;
|
|
218
254
|
}
|
|
219
|
-
static checkPostBody(schema, isRequired = false) {
|
|
255
|
+
static checkPostBody(schema, isRequired = false, isCopilot = false) {
|
|
220
256
|
var _a;
|
|
221
257
|
const paramResult = {
|
|
222
258
|
requiredNum: 0,
|
|
@@ -227,6 +263,10 @@ class Utils {
|
|
|
227
263
|
return paramResult;
|
|
228
264
|
}
|
|
229
265
|
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
266
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
267
|
+
paramResult.isValid = false;
|
|
268
|
+
return paramResult;
|
|
269
|
+
}
|
|
230
270
|
if (schema.type === "string" ||
|
|
231
271
|
schema.type === "integer" ||
|
|
232
272
|
schema.type === "boolean" ||
|
|
@@ -245,19 +285,22 @@ class Utils {
|
|
|
245
285
|
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
246
286
|
isRequired = true;
|
|
247
287
|
}
|
|
248
|
-
const result = Utils.checkPostBody(properties[property], isRequired);
|
|
288
|
+
const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
|
|
249
289
|
paramResult.requiredNum += result.requiredNum;
|
|
250
290
|
paramResult.optionalNum += result.optionalNum;
|
|
251
291
|
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
252
292
|
}
|
|
253
293
|
}
|
|
254
294
|
else {
|
|
255
|
-
if (isRequiredWithoutDefault) {
|
|
295
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
256
296
|
paramResult.isValid = false;
|
|
257
297
|
}
|
|
258
298
|
}
|
|
259
299
|
return paramResult;
|
|
260
300
|
}
|
|
301
|
+
static containMultipleMediaTypes(bodyObject) {
|
|
302
|
+
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
303
|
+
}
|
|
261
304
|
/**
|
|
262
305
|
* Checks if the given API is supported.
|
|
263
306
|
* @param {string} method - The HTTP method of the API.
|
|
@@ -272,32 +315,40 @@ class Utils {
|
|
|
272
315
|
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
273
316
|
* 6. only support request body with “application/json” content type
|
|
274
317
|
*/
|
|
275
|
-
static isSupportedApi(method, path, spec,
|
|
318
|
+
static isSupportedApi(method, path, spec, options) {
|
|
319
|
+
var _a;
|
|
276
320
|
const pathObj = spec.paths[path];
|
|
277
321
|
method = method.toLocaleLowerCase();
|
|
278
322
|
if (pathObj) {
|
|
279
|
-
if ((
|
|
280
|
-
pathObj[method]) {
|
|
323
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
|
|
281
324
|
const securities = pathObj[method].security;
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
325
|
+
const isTeamsAi = options.projectType === ProjectType.TeamsAi;
|
|
326
|
+
const isCopilot = options.projectType === ProjectType.Copilot;
|
|
327
|
+
// Teams AI project doesn't care about auth, it will use authProvider for user to implement
|
|
328
|
+
if (!isTeamsAi) {
|
|
329
|
+
const authArray = Utils.getAuthArray(securities, spec);
|
|
330
|
+
if (!Utils.isSupportedAuth(authArray, options)) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
285
333
|
}
|
|
286
334
|
const operationObject = pathObj[method];
|
|
287
|
-
if (!allowMissingId && !operationObject.operationId) {
|
|
335
|
+
if (!options.allowMissingId && !operationObject.operationId) {
|
|
288
336
|
return false;
|
|
289
337
|
}
|
|
290
338
|
const paramObject = operationObject.parameters;
|
|
291
339
|
const requestBody = operationObject.requestBody;
|
|
292
340
|
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
293
|
-
|
|
294
|
-
if (mediaTypesCount > 1) {
|
|
341
|
+
if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
|
|
295
342
|
return false;
|
|
296
343
|
}
|
|
297
|
-
const responseJson = Utils.getResponseJson(operationObject);
|
|
344
|
+
const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
|
|
298
345
|
if (Object.keys(responseJson).length === 0) {
|
|
299
346
|
return false;
|
|
300
347
|
}
|
|
348
|
+
// Teams AI project doesn't care about request parameters/body
|
|
349
|
+
if (isTeamsAi) {
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
301
352
|
let requestBodyParamResult = {
|
|
302
353
|
requiredNum: 0,
|
|
303
354
|
optionalNum: 0,
|
|
@@ -305,18 +356,26 @@ class Utils {
|
|
|
305
356
|
};
|
|
306
357
|
if (requestJsonBody) {
|
|
307
358
|
const requestBodySchema = requestJsonBody.schema;
|
|
308
|
-
|
|
359
|
+
if (isCopilot && requestBodySchema.type !== "object") {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
|
|
309
363
|
}
|
|
310
364
|
if (!requestBodyParamResult.isValid) {
|
|
311
365
|
return false;
|
|
312
366
|
}
|
|
313
|
-
const paramResult = Utils.checkParameters(paramObject);
|
|
367
|
+
const paramResult = Utils.checkParameters(paramObject, isCopilot);
|
|
314
368
|
if (!paramResult.isValid) {
|
|
315
369
|
return false;
|
|
316
370
|
}
|
|
371
|
+
// Copilot support arbitrary parameters
|
|
372
|
+
if (isCopilot) {
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
317
375
|
if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
|
|
318
|
-
if (allowMultipleParameters &&
|
|
319
|
-
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
376
|
+
if (options.allowMultipleParameters &&
|
|
377
|
+
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
378
|
+
ConstantString.SMERequiredParamsMaxNum) {
|
|
320
379
|
return true;
|
|
321
380
|
}
|
|
322
381
|
return false;
|
|
@@ -335,29 +394,20 @@ class Utils {
|
|
|
335
394
|
}
|
|
336
395
|
return false;
|
|
337
396
|
}
|
|
338
|
-
static isSupportedAuth(
|
|
339
|
-
if (
|
|
397
|
+
static isSupportedAuth(authSchemeArray, options) {
|
|
398
|
+
if (authSchemeArray.length === 0) {
|
|
340
399
|
return true;
|
|
341
400
|
}
|
|
342
|
-
if (allowAPIKeyAuth || allowOauth2) {
|
|
401
|
+
if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
|
|
343
402
|
// Currently we don't support multiple auth in one operation
|
|
344
|
-
if (
|
|
403
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
345
404
|
return false;
|
|
346
405
|
}
|
|
347
|
-
for (const auths of
|
|
406
|
+
for (const auths of authSchemeArray) {
|
|
348
407
|
if (auths.length === 1) {
|
|
349
|
-
if (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
else if (!allowAPIKeyAuth &&
|
|
353
|
-
allowOauth2 &&
|
|
354
|
-
Utils.isBearerTokenAuth(auths[0].authSchema)) {
|
|
355
|
-
return true;
|
|
356
|
-
}
|
|
357
|
-
else if (allowAPIKeyAuth &&
|
|
358
|
-
allowOauth2 &&
|
|
359
|
-
(Utils.isAPIKeyAuth(auths[0].authSchema) ||
|
|
360
|
-
Utils.isBearerTokenAuth(auths[0].authSchema))) {
|
|
408
|
+
if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
409
|
+
(options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
|
|
410
|
+
(options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
|
|
361
411
|
return true;
|
|
362
412
|
}
|
|
363
413
|
}
|
|
@@ -365,13 +415,17 @@ class Utils {
|
|
|
365
415
|
}
|
|
366
416
|
return false;
|
|
367
417
|
}
|
|
368
|
-
static
|
|
369
|
-
return
|
|
418
|
+
static isBearerTokenAuth(authScheme) {
|
|
419
|
+
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
370
420
|
}
|
|
371
|
-
static
|
|
372
|
-
return
|
|
373
|
-
|
|
374
|
-
|
|
421
|
+
static isAPIKeyAuth(authScheme) {
|
|
422
|
+
return authScheme.type === "apiKey";
|
|
423
|
+
}
|
|
424
|
+
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
425
|
+
if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
|
|
426
|
+
return true;
|
|
427
|
+
}
|
|
428
|
+
return false;
|
|
375
429
|
}
|
|
376
430
|
static getAuthArray(securities, spec) {
|
|
377
431
|
var _a;
|
|
@@ -384,7 +438,7 @@ class Utils {
|
|
|
384
438
|
for (const name in security) {
|
|
385
439
|
const auth = securitySchemas[name];
|
|
386
440
|
authArray.push({
|
|
387
|
-
|
|
441
|
+
authScheme: auth,
|
|
388
442
|
name: name,
|
|
389
443
|
});
|
|
390
444
|
}
|
|
@@ -399,18 +453,19 @@ class Utils {
|
|
|
399
453
|
static updateFirstLetter(str) {
|
|
400
454
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
401
455
|
}
|
|
402
|
-
static getResponseJson(operationObject) {
|
|
456
|
+
static getResponseJson(operationObject, isTeamsAiProject = false) {
|
|
403
457
|
var _a, _b;
|
|
404
458
|
let json = {};
|
|
405
459
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
406
460
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
407
|
-
const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
|
|
408
|
-
if (mediaTypesCount > 1) {
|
|
409
|
-
return {};
|
|
410
|
-
}
|
|
411
461
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
412
462
|
json = responseObject.content["application/json"];
|
|
413
|
-
|
|
463
|
+
if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
|
|
464
|
+
json = {};
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
414
469
|
}
|
|
415
470
|
}
|
|
416
471
|
return json;
|
|
@@ -484,7 +539,7 @@ class Utils {
|
|
|
484
539
|
}
|
|
485
540
|
return errors;
|
|
486
541
|
}
|
|
487
|
-
static validateServer(spec,
|
|
542
|
+
static validateServer(spec, options) {
|
|
488
543
|
const errors = [];
|
|
489
544
|
let hasTopLevelServers = false;
|
|
490
545
|
let hasPathLevelServers = false;
|
|
@@ -505,7 +560,7 @@ class Utils {
|
|
|
505
560
|
}
|
|
506
561
|
for (const method in methods) {
|
|
507
562
|
const operationObject = methods[method];
|
|
508
|
-
if (Utils.isSupportedApi(method, path, spec,
|
|
563
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
509
564
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
510
565
|
hasOperationLevelServers = true;
|
|
511
566
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -548,6 +603,7 @@ class Utils {
|
|
|
548
603
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
549
604
|
}
|
|
550
605
|
if (isRequired && schema.default === undefined) {
|
|
606
|
+
parameter.isRequired = true;
|
|
551
607
|
requiredParams.push(parameter);
|
|
552
608
|
}
|
|
553
609
|
else {
|
|
@@ -592,7 +648,7 @@ class Utils {
|
|
|
592
648
|
param.value = schema.default;
|
|
593
649
|
}
|
|
594
650
|
}
|
|
595
|
-
static parseApiInfo(operationItem,
|
|
651
|
+
static parseApiInfo(operationItem, options) {
|
|
596
652
|
var _a, _b;
|
|
597
653
|
const requiredParams = [];
|
|
598
654
|
const optionalParams = [];
|
|
@@ -606,11 +662,12 @@ class Utils {
|
|
|
606
662
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
607
663
|
};
|
|
608
664
|
const schema = param.schema;
|
|
609
|
-
if (allowMultipleParameters && schema) {
|
|
665
|
+
if (options.allowMultipleParameters && schema) {
|
|
610
666
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
611
667
|
}
|
|
612
668
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
613
669
|
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
670
|
+
parameter.isRequired = true;
|
|
614
671
|
requiredParams.push(parameter);
|
|
615
672
|
}
|
|
616
673
|
else {
|
|
@@ -624,7 +681,7 @@ class Utils {
|
|
|
624
681
|
const requestJson = requestBody.content["application/json"];
|
|
625
682
|
if (Object.keys(requestJson).length !== 0) {
|
|
626
683
|
const schema = requestJson.schema;
|
|
627
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
684
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
628
685
|
requiredParams.push(...requiredP);
|
|
629
686
|
optionalParams.push(...optionalP);
|
|
630
687
|
}
|
|
@@ -655,14 +712,13 @@ class Utils {
|
|
|
655
712
|
}
|
|
656
713
|
return [command, warning];
|
|
657
714
|
}
|
|
658
|
-
static listSupportedAPIs(spec,
|
|
715
|
+
static listSupportedAPIs(spec, options) {
|
|
659
716
|
const paths = spec.paths;
|
|
660
717
|
const result = {};
|
|
661
718
|
for (const path in paths) {
|
|
662
719
|
const methods = paths[path];
|
|
663
720
|
for (const method in methods) {
|
|
664
|
-
|
|
665
|
-
if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
|
|
721
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
666
722
|
const operationObject = methods[method];
|
|
667
723
|
result[`${method.toUpperCase()} ${path}`] = operationObject;
|
|
668
724
|
}
|
|
@@ -670,7 +726,7 @@ class Utils {
|
|
|
670
726
|
}
|
|
671
727
|
return result;
|
|
672
728
|
}
|
|
673
|
-
static validateSpec(spec, parser, isSwaggerFile,
|
|
729
|
+
static validateSpec(spec, parser, isSwaggerFile, options) {
|
|
674
730
|
const errors = [];
|
|
675
731
|
const warnings = [];
|
|
676
732
|
if (isSwaggerFile) {
|
|
@@ -680,7 +736,7 @@ class Utils {
|
|
|
680
736
|
});
|
|
681
737
|
}
|
|
682
738
|
// Server validation
|
|
683
|
-
const serverErrors = Utils.validateServer(spec,
|
|
739
|
+
const serverErrors = Utils.validateServer(spec, options);
|
|
684
740
|
errors.push(...serverErrors);
|
|
685
741
|
// Remote reference not supported
|
|
686
742
|
const refPaths = parser.$refs.paths();
|
|
@@ -693,7 +749,7 @@ class Utils {
|
|
|
693
749
|
});
|
|
694
750
|
}
|
|
695
751
|
// No supported API
|
|
696
|
-
const apiMap = Utils.listSupportedAPIs(spec,
|
|
752
|
+
const apiMap = Utils.listSupportedAPIs(spec, options);
|
|
697
753
|
if (Object.keys(apiMap).length === 0) {
|
|
698
754
|
errors.push({
|
|
699
755
|
type: ErrorType.NoSupportedApi,
|
|
@@ -745,6 +801,19 @@ class Utils {
|
|
|
745
801
|
}
|
|
746
802
|
return safeRegistrationIdEnvName;
|
|
747
803
|
}
|
|
804
|
+
static getAllAPICount(spec) {
|
|
805
|
+
let count = 0;
|
|
806
|
+
const paths = spec.paths;
|
|
807
|
+
for (const path in paths) {
|
|
808
|
+
const methods = paths[path];
|
|
809
|
+
for (const method in methods) {
|
|
810
|
+
if (ConstantString.AllOperationMethods.includes(method)) {
|
|
811
|
+
count++;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
return count;
|
|
816
|
+
}
|
|
748
817
|
}
|
|
749
818
|
|
|
750
819
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -763,7 +832,10 @@ class SpecParser {
|
|
|
763
832
|
allowSwagger: false,
|
|
764
833
|
allowAPIKeyAuth: false,
|
|
765
834
|
allowMultipleParameters: false,
|
|
835
|
+
allowBearerTokenAuth: false,
|
|
766
836
|
allowOauth2: false,
|
|
837
|
+
allowMethods: ["get", "post"],
|
|
838
|
+
projectType: ProjectType.SME,
|
|
767
839
|
};
|
|
768
840
|
this.pathOrSpec = pathOrDoc;
|
|
769
841
|
this.parser = new SwaggerParser();
|
|
@@ -801,7 +873,7 @@ class SpecParser {
|
|
|
801
873
|
],
|
|
802
874
|
};
|
|
803
875
|
}
|
|
804
|
-
return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options
|
|
876
|
+
return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
|
|
805
877
|
}
|
|
806
878
|
catch (err) {
|
|
807
879
|
throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
|
|
@@ -822,7 +894,7 @@ class SpecParser {
|
|
|
822
894
|
if (!operationId) {
|
|
823
895
|
continue;
|
|
824
896
|
}
|
|
825
|
-
const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options
|
|
897
|
+
const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
|
|
826
898
|
const apiInfo = {
|
|
827
899
|
method: method,
|
|
828
900
|
path: path,
|
|
@@ -854,12 +926,36 @@ class SpecParser {
|
|
|
854
926
|
throw new Error("Method not implemented.");
|
|
855
927
|
});
|
|
856
928
|
}
|
|
929
|
+
/**
|
|
930
|
+
* Generate specs according to the filters.
|
|
931
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
932
|
+
*/
|
|
933
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
934
|
+
getFilteredSpecs(filter, signal) {
|
|
935
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
936
|
+
throw new Error("Method not implemented.");
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
941
|
+
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
942
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
943
|
+
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
944
|
+
* @param pluginFilePath File path of the api plugin file to generate.
|
|
945
|
+
*/
|
|
946
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
947
|
+
generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
948
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
949
|
+
throw new Error("Method not implemented.");
|
|
950
|
+
});
|
|
951
|
+
}
|
|
857
952
|
/**
|
|
858
953
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
859
954
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
860
955
|
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
861
956
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
862
957
|
* @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
|
|
958
|
+
* @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
|
|
863
959
|
*/
|
|
864
960
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
865
961
|
generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
@@ -883,11 +979,169 @@ class SpecParser {
|
|
|
883
979
|
if (this.apiMap !== undefined) {
|
|
884
980
|
return this.apiMap;
|
|
885
981
|
}
|
|
886
|
-
const result = Utils.listSupportedAPIs(spec, this.options
|
|
982
|
+
const result = Utils.listSupportedAPIs(spec, this.options);
|
|
887
983
|
this.apiMap = result;
|
|
888
984
|
return result;
|
|
889
985
|
}
|
|
890
986
|
}
|
|
891
987
|
|
|
892
|
-
|
|
988
|
+
// Copyright (c) Microsoft Corporation.
|
|
989
|
+
class AdaptiveCardGenerator {
|
|
990
|
+
static generateAdaptiveCard(operationItem) {
|
|
991
|
+
try {
|
|
992
|
+
const json = Utils.getResponseJson(operationItem);
|
|
993
|
+
let cardBody = [];
|
|
994
|
+
let schema = json.schema;
|
|
995
|
+
let jsonPath = "$";
|
|
996
|
+
if (schema && Object.keys(schema).length > 0) {
|
|
997
|
+
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
998
|
+
if (jsonPath !== "$") {
|
|
999
|
+
schema = schema.properties[jsonPath];
|
|
1000
|
+
}
|
|
1001
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
1002
|
+
}
|
|
1003
|
+
// if no schema, try to use example value
|
|
1004
|
+
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
1005
|
+
cardBody = [
|
|
1006
|
+
{
|
|
1007
|
+
type: ConstantString.TextBlockType,
|
|
1008
|
+
text: "${jsonStringify($root)}",
|
|
1009
|
+
wrap: true,
|
|
1010
|
+
},
|
|
1011
|
+
];
|
|
1012
|
+
}
|
|
1013
|
+
// if no example value, use default success response
|
|
1014
|
+
if (cardBody.length === 0) {
|
|
1015
|
+
cardBody = [
|
|
1016
|
+
{
|
|
1017
|
+
type: ConstantString.TextBlockType,
|
|
1018
|
+
text: "success",
|
|
1019
|
+
wrap: true,
|
|
1020
|
+
},
|
|
1021
|
+
];
|
|
1022
|
+
}
|
|
1023
|
+
const fullCard = {
|
|
1024
|
+
type: ConstantString.AdaptiveCardType,
|
|
1025
|
+
$schema: ConstantString.AdaptiveCardSchema,
|
|
1026
|
+
version: ConstantString.AdaptiveCardVersion,
|
|
1027
|
+
body: cardBody,
|
|
1028
|
+
};
|
|
1029
|
+
return [fullCard, jsonPath];
|
|
1030
|
+
}
|
|
1031
|
+
catch (err) {
|
|
1032
|
+
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
1036
|
+
if (schema.type === "array") {
|
|
1037
|
+
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
1038
|
+
if (Object.keys(schema.items).length === 0) {
|
|
1039
|
+
return [
|
|
1040
|
+
{
|
|
1041
|
+
type: ConstantString.TextBlockType,
|
|
1042
|
+
text: name ? `${name}: \${jsonStringify(${name})}` : "result: ${jsonStringify($root)}",
|
|
1043
|
+
wrap: true,
|
|
1044
|
+
},
|
|
1045
|
+
];
|
|
1046
|
+
}
|
|
1047
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
1048
|
+
const template = {
|
|
1049
|
+
type: ConstantString.ContainerType,
|
|
1050
|
+
$data: name ? `\${${name}}` : "${$root}",
|
|
1051
|
+
items: Array(),
|
|
1052
|
+
};
|
|
1053
|
+
template.items.push(...obj);
|
|
1054
|
+
return [template];
|
|
1055
|
+
}
|
|
1056
|
+
// some schema may not contain type but contain properties
|
|
1057
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
1058
|
+
const { properties } = schema;
|
|
1059
|
+
const result = [];
|
|
1060
|
+
for (const property in properties) {
|
|
1061
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
1062
|
+
result.push(...obj);
|
|
1063
|
+
}
|
|
1064
|
+
if (schema.additionalProperties) {
|
|
1065
|
+
// TODO: better ways to handler warnings.
|
|
1066
|
+
console.warn(ConstantString.AdditionalPropertiesNotSupported);
|
|
1067
|
+
}
|
|
1068
|
+
return result;
|
|
1069
|
+
}
|
|
1070
|
+
if (schema.type === "string" ||
|
|
1071
|
+
schema.type === "integer" ||
|
|
1072
|
+
schema.type === "boolean" ||
|
|
1073
|
+
schema.type === "number") {
|
|
1074
|
+
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1075
|
+
// string in root: "ddd"
|
|
1076
|
+
let text = "result: ${$root}";
|
|
1077
|
+
if (name) {
|
|
1078
|
+
// object { id: "1" }
|
|
1079
|
+
text = `${name}: \${if(${name}, ${name}, 'N/A')}`;
|
|
1080
|
+
if (parentArrayName) {
|
|
1081
|
+
// object types inside array: { tags: ["id": 1, "name": "name"] }
|
|
1082
|
+
text = `${parentArrayName}.${text}`;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
else if (parentArrayName) {
|
|
1086
|
+
// string array: photoUrls: ["1", "2"]
|
|
1087
|
+
text = `${parentArrayName}: ` + "${$data}";
|
|
1088
|
+
}
|
|
1089
|
+
return [
|
|
1090
|
+
{
|
|
1091
|
+
type: ConstantString.TextBlockType,
|
|
1092
|
+
text,
|
|
1093
|
+
wrap: true,
|
|
1094
|
+
},
|
|
1095
|
+
];
|
|
1096
|
+
}
|
|
1097
|
+
else {
|
|
1098
|
+
if (name) {
|
|
1099
|
+
return [
|
|
1100
|
+
{
|
|
1101
|
+
type: "Image",
|
|
1102
|
+
url: `\${${name}}`,
|
|
1103
|
+
$when: `\${${name} != null}`,
|
|
1104
|
+
},
|
|
1105
|
+
];
|
|
1106
|
+
}
|
|
1107
|
+
else {
|
|
1108
|
+
return [
|
|
1109
|
+
{
|
|
1110
|
+
type: "Image",
|
|
1111
|
+
url: "${$data}",
|
|
1112
|
+
$when: "${$data != null}",
|
|
1113
|
+
},
|
|
1114
|
+
];
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
1119
|
+
throw new Error(Utils.format(ConstantString.SchemaNotSupported, JSON.stringify(schema)));
|
|
1120
|
+
}
|
|
1121
|
+
throw new Error(Utils.format(ConstantString.UnknownSchema, JSON.stringify(schema)));
|
|
1122
|
+
}
|
|
1123
|
+
// Find the first array property in the response schema object with the well-known name
|
|
1124
|
+
static getResponseJsonPathFromSchema(schema) {
|
|
1125
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
1126
|
+
const { properties } = schema;
|
|
1127
|
+
for (const property in properties) {
|
|
1128
|
+
const schema = properties[property];
|
|
1129
|
+
if (schema.type === "array" &&
|
|
1130
|
+
Utils.isWellKnownName(property, ConstantString.WellknownResultNames)) {
|
|
1131
|
+
return property;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
return "$";
|
|
1136
|
+
}
|
|
1137
|
+
static isImageUrlProperty(schema, name, parentArrayName) {
|
|
1138
|
+
const propertyName = name ? name : parentArrayName;
|
|
1139
|
+
return (!!propertyName &&
|
|
1140
|
+
schema.type === "string" &&
|
|
1141
|
+
Utils.isWellKnownName(propertyName, ConstantString.WellknownImageName) &&
|
|
1142
|
+
(propertyName.toLocaleLowerCase().indexOf("url") >= 0 || schema.format === "uri"));
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
export { AdaptiveCardGenerator, ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|
|
893
1147
|
//# sourceMappingURL=index.esm5.js.map
|