@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.esm2017.js
CHANGED
|
@@ -15,7 +15,8 @@ var ErrorType;
|
|
|
15
15
|
ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
|
|
16
16
|
ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
|
|
17
17
|
ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
|
|
18
|
-
ErrorType["
|
|
18
|
+
ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
|
|
19
|
+
ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
|
|
19
20
|
ErrorType["ListFailed"] = "list-failed";
|
|
20
21
|
ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
|
|
21
22
|
ErrorType["FilterSpecFailed"] = "filter-spec-failed";
|
|
@@ -23,6 +24,7 @@ var ErrorType;
|
|
|
23
24
|
ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
|
|
24
25
|
ErrorType["GenerateFailed"] = "generate-failed";
|
|
25
26
|
ErrorType["ValidateFailed"] = "validate-failed";
|
|
27
|
+
ErrorType["GetSpecFailed"] = "get-spec-failed";
|
|
26
28
|
ErrorType["Cancelled"] = "cancelled";
|
|
27
29
|
ErrorType["Unknown"] = "unknown";
|
|
28
30
|
})(ErrorType || (ErrorType = {}));
|
|
@@ -45,7 +47,13 @@ var ValidationStatus;
|
|
|
45
47
|
ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
|
|
46
48
|
ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
|
|
47
49
|
ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
|
|
48
|
-
})(ValidationStatus || (ValidationStatus = {}));
|
|
50
|
+
})(ValidationStatus || (ValidationStatus = {}));
|
|
51
|
+
var ProjectType;
|
|
52
|
+
(function (ProjectType) {
|
|
53
|
+
ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
|
|
54
|
+
ProjectType[ProjectType["SME"] = 1] = "SME";
|
|
55
|
+
ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
|
|
56
|
+
})(ProjectType || (ProjectType = {}));
|
|
49
57
|
|
|
50
58
|
// Copyright (c) Microsoft Corporation.
|
|
51
59
|
class SpecParserError extends Error {
|
|
@@ -72,7 +80,9 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
|
|
|
72
80
|
ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
|
|
73
81
|
ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
|
|
74
82
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
75
|
-
ConstantString.
|
|
83
|
+
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
84
|
+
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
85
|
+
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
76
86
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
77
87
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
78
88
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
@@ -84,6 +94,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
|
84
94
|
ConstantString.TextBlockType = "TextBlock";
|
|
85
95
|
ConstantString.ContainerType = "Container";
|
|
86
96
|
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
97
|
+
ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
|
|
87
98
|
ConstantString.ResponseCodeFor20X = [
|
|
88
99
|
"200",
|
|
89
100
|
"201",
|
|
@@ -143,11 +154,23 @@ ConstantString.FullDescriptionMaxLens = 4000;
|
|
|
143
154
|
ConstantString.CommandDescriptionMaxLens = 128;
|
|
144
155
|
ConstantString.ParameterDescriptionMaxLens = 128;
|
|
145
156
|
ConstantString.CommandTitleMaxLens = 32;
|
|
146
|
-
ConstantString.ParameterTitleMaxLens = 32;
|
|
157
|
+
ConstantString.ParameterTitleMaxLens = 32;
|
|
158
|
+
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
147
159
|
|
|
148
160
|
// Copyright (c) Microsoft Corporation.
|
|
149
161
|
class Utils {
|
|
150
|
-
static
|
|
162
|
+
static hasNestedObjectInSchema(schema) {
|
|
163
|
+
if (schema.type === "object") {
|
|
164
|
+
for (const property in schema.properties) {
|
|
165
|
+
const nestedSchema = schema.properties[property];
|
|
166
|
+
if (nestedSchema.type === "object") {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
static checkParameters(paramObject, isCopilot) {
|
|
151
174
|
const paramResult = {
|
|
152
175
|
requiredNum: 0,
|
|
153
176
|
optionalNum: 0,
|
|
@@ -159,7 +182,20 @@ class Utils {
|
|
|
159
182
|
for (let i = 0; i < paramObject.length; i++) {
|
|
160
183
|
const param = paramObject[i];
|
|
161
184
|
const schema = param.schema;
|
|
185
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
186
|
+
paramResult.isValid = false;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
162
189
|
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
190
|
+
if (isCopilot) {
|
|
191
|
+
if (isRequiredWithoutDefault) {
|
|
192
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
196
|
+
}
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
163
199
|
if (param.in === "header" || param.in === "cookie") {
|
|
164
200
|
if (isRequiredWithoutDefault) {
|
|
165
201
|
paramResult.isValid = false;
|
|
@@ -186,7 +222,7 @@ class Utils {
|
|
|
186
222
|
}
|
|
187
223
|
return paramResult;
|
|
188
224
|
}
|
|
189
|
-
static checkPostBody(schema, isRequired = false) {
|
|
225
|
+
static checkPostBody(schema, isRequired = false, isCopilot = false) {
|
|
190
226
|
var _a;
|
|
191
227
|
const paramResult = {
|
|
192
228
|
requiredNum: 0,
|
|
@@ -197,6 +233,10 @@ class Utils {
|
|
|
197
233
|
return paramResult;
|
|
198
234
|
}
|
|
199
235
|
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
236
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
237
|
+
paramResult.isValid = false;
|
|
238
|
+
return paramResult;
|
|
239
|
+
}
|
|
200
240
|
if (schema.type === "string" ||
|
|
201
241
|
schema.type === "integer" ||
|
|
202
242
|
schema.type === "boolean" ||
|
|
@@ -215,19 +255,22 @@ class Utils {
|
|
|
215
255
|
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
216
256
|
isRequired = true;
|
|
217
257
|
}
|
|
218
|
-
const result = Utils.checkPostBody(properties[property], isRequired);
|
|
258
|
+
const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
|
|
219
259
|
paramResult.requiredNum += result.requiredNum;
|
|
220
260
|
paramResult.optionalNum += result.optionalNum;
|
|
221
261
|
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
222
262
|
}
|
|
223
263
|
}
|
|
224
264
|
else {
|
|
225
|
-
if (isRequiredWithoutDefault) {
|
|
265
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
226
266
|
paramResult.isValid = false;
|
|
227
267
|
}
|
|
228
268
|
}
|
|
229
269
|
return paramResult;
|
|
230
270
|
}
|
|
271
|
+
static containMultipleMediaTypes(bodyObject) {
|
|
272
|
+
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
273
|
+
}
|
|
231
274
|
/**
|
|
232
275
|
* Checks if the given API is supported.
|
|
233
276
|
* @param {string} method - The HTTP method of the API.
|
|
@@ -242,32 +285,40 @@ class Utils {
|
|
|
242
285
|
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
243
286
|
* 6. only support request body with “application/json” content type
|
|
244
287
|
*/
|
|
245
|
-
static isSupportedApi(method, path, spec,
|
|
288
|
+
static isSupportedApi(method, path, spec, options) {
|
|
289
|
+
var _a;
|
|
246
290
|
const pathObj = spec.paths[path];
|
|
247
291
|
method = method.toLocaleLowerCase();
|
|
248
292
|
if (pathObj) {
|
|
249
|
-
if ((
|
|
250
|
-
pathObj[method]) {
|
|
293
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
|
|
251
294
|
const securities = pathObj[method].security;
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
295
|
+
const isTeamsAi = options.projectType === ProjectType.TeamsAi;
|
|
296
|
+
const isCopilot = options.projectType === ProjectType.Copilot;
|
|
297
|
+
// Teams AI project doesn't care about auth, it will use authProvider for user to implement
|
|
298
|
+
if (!isTeamsAi) {
|
|
299
|
+
const authArray = Utils.getAuthArray(securities, spec);
|
|
300
|
+
if (!Utils.isSupportedAuth(authArray, options)) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
255
303
|
}
|
|
256
304
|
const operationObject = pathObj[method];
|
|
257
|
-
if (!allowMissingId && !operationObject.operationId) {
|
|
305
|
+
if (!options.allowMissingId && !operationObject.operationId) {
|
|
258
306
|
return false;
|
|
259
307
|
}
|
|
260
308
|
const paramObject = operationObject.parameters;
|
|
261
309
|
const requestBody = operationObject.requestBody;
|
|
262
310
|
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
263
|
-
|
|
264
|
-
if (mediaTypesCount > 1) {
|
|
311
|
+
if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
|
|
265
312
|
return false;
|
|
266
313
|
}
|
|
267
|
-
const responseJson = Utils.getResponseJson(operationObject);
|
|
314
|
+
const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
|
|
268
315
|
if (Object.keys(responseJson).length === 0) {
|
|
269
316
|
return false;
|
|
270
317
|
}
|
|
318
|
+
// Teams AI project doesn't care about request parameters/body
|
|
319
|
+
if (isTeamsAi) {
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
271
322
|
let requestBodyParamResult = {
|
|
272
323
|
requiredNum: 0,
|
|
273
324
|
optionalNum: 0,
|
|
@@ -275,18 +326,26 @@ class Utils {
|
|
|
275
326
|
};
|
|
276
327
|
if (requestJsonBody) {
|
|
277
328
|
const requestBodySchema = requestJsonBody.schema;
|
|
278
|
-
|
|
329
|
+
if (isCopilot && requestBodySchema.type !== "object") {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
|
|
279
333
|
}
|
|
280
334
|
if (!requestBodyParamResult.isValid) {
|
|
281
335
|
return false;
|
|
282
336
|
}
|
|
283
|
-
const paramResult = Utils.checkParameters(paramObject);
|
|
337
|
+
const paramResult = Utils.checkParameters(paramObject, isCopilot);
|
|
284
338
|
if (!paramResult.isValid) {
|
|
285
339
|
return false;
|
|
286
340
|
}
|
|
341
|
+
// Copilot support arbitrary parameters
|
|
342
|
+
if (isCopilot) {
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
287
345
|
if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
|
|
288
|
-
if (allowMultipleParameters &&
|
|
289
|
-
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
346
|
+
if (options.allowMultipleParameters &&
|
|
347
|
+
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
348
|
+
ConstantString.SMERequiredParamsMaxNum) {
|
|
290
349
|
return true;
|
|
291
350
|
}
|
|
292
351
|
return false;
|
|
@@ -305,29 +364,20 @@ class Utils {
|
|
|
305
364
|
}
|
|
306
365
|
return false;
|
|
307
366
|
}
|
|
308
|
-
static isSupportedAuth(
|
|
309
|
-
if (
|
|
367
|
+
static isSupportedAuth(authSchemeArray, options) {
|
|
368
|
+
if (authSchemeArray.length === 0) {
|
|
310
369
|
return true;
|
|
311
370
|
}
|
|
312
|
-
if (allowAPIKeyAuth || allowOauth2) {
|
|
371
|
+
if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
|
|
313
372
|
// Currently we don't support multiple auth in one operation
|
|
314
|
-
if (
|
|
373
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
315
374
|
return false;
|
|
316
375
|
}
|
|
317
|
-
for (const auths of
|
|
376
|
+
for (const auths of authSchemeArray) {
|
|
318
377
|
if (auths.length === 1) {
|
|
319
|
-
if (
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
else if (!allowAPIKeyAuth &&
|
|
323
|
-
allowOauth2 &&
|
|
324
|
-
Utils.isBearerTokenAuth(auths[0].authSchema)) {
|
|
325
|
-
return true;
|
|
326
|
-
}
|
|
327
|
-
else if (allowAPIKeyAuth &&
|
|
328
|
-
allowOauth2 &&
|
|
329
|
-
(Utils.isAPIKeyAuth(auths[0].authSchema) ||
|
|
330
|
-
Utils.isBearerTokenAuth(auths[0].authSchema))) {
|
|
378
|
+
if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
379
|
+
(options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
|
|
380
|
+
(options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
|
|
331
381
|
return true;
|
|
332
382
|
}
|
|
333
383
|
}
|
|
@@ -335,13 +385,17 @@ class Utils {
|
|
|
335
385
|
}
|
|
336
386
|
return false;
|
|
337
387
|
}
|
|
338
|
-
static
|
|
339
|
-
return
|
|
388
|
+
static isBearerTokenAuth(authScheme) {
|
|
389
|
+
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
390
|
+
}
|
|
391
|
+
static isAPIKeyAuth(authScheme) {
|
|
392
|
+
return authScheme.type === "apiKey";
|
|
340
393
|
}
|
|
341
|
-
static
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
394
|
+
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
395
|
+
if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
return false;
|
|
345
399
|
}
|
|
346
400
|
static getAuthArray(securities, spec) {
|
|
347
401
|
var _a;
|
|
@@ -354,7 +408,7 @@ class Utils {
|
|
|
354
408
|
for (const name in security) {
|
|
355
409
|
const auth = securitySchemas[name];
|
|
356
410
|
authArray.push({
|
|
357
|
-
|
|
411
|
+
authScheme: auth,
|
|
358
412
|
name: name,
|
|
359
413
|
});
|
|
360
414
|
}
|
|
@@ -369,18 +423,19 @@ class Utils {
|
|
|
369
423
|
static updateFirstLetter(str) {
|
|
370
424
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
371
425
|
}
|
|
372
|
-
static getResponseJson(operationObject) {
|
|
426
|
+
static getResponseJson(operationObject, isTeamsAiProject = false) {
|
|
373
427
|
var _a, _b;
|
|
374
428
|
let json = {};
|
|
375
429
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
376
430
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
377
|
-
const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
|
|
378
|
-
if (mediaTypesCount > 1) {
|
|
379
|
-
return {};
|
|
380
|
-
}
|
|
381
431
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
382
432
|
json = responseObject.content["application/json"];
|
|
383
|
-
|
|
433
|
+
if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
|
|
434
|
+
json = {};
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
384
439
|
}
|
|
385
440
|
}
|
|
386
441
|
return json;
|
|
@@ -454,7 +509,7 @@ class Utils {
|
|
|
454
509
|
}
|
|
455
510
|
return errors;
|
|
456
511
|
}
|
|
457
|
-
static validateServer(spec,
|
|
512
|
+
static validateServer(spec, options) {
|
|
458
513
|
const errors = [];
|
|
459
514
|
let hasTopLevelServers = false;
|
|
460
515
|
let hasPathLevelServers = false;
|
|
@@ -475,7 +530,7 @@ class Utils {
|
|
|
475
530
|
}
|
|
476
531
|
for (const method in methods) {
|
|
477
532
|
const operationObject = methods[method];
|
|
478
|
-
if (Utils.isSupportedApi(method, path, spec,
|
|
533
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
479
534
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
480
535
|
hasOperationLevelServers = true;
|
|
481
536
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -518,6 +573,7 @@ class Utils {
|
|
|
518
573
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
519
574
|
}
|
|
520
575
|
if (isRequired && schema.default === undefined) {
|
|
576
|
+
parameter.isRequired = true;
|
|
521
577
|
requiredParams.push(parameter);
|
|
522
578
|
}
|
|
523
579
|
else {
|
|
@@ -562,7 +618,7 @@ class Utils {
|
|
|
562
618
|
param.value = schema.default;
|
|
563
619
|
}
|
|
564
620
|
}
|
|
565
|
-
static parseApiInfo(operationItem,
|
|
621
|
+
static parseApiInfo(operationItem, options) {
|
|
566
622
|
var _a, _b;
|
|
567
623
|
const requiredParams = [];
|
|
568
624
|
const optionalParams = [];
|
|
@@ -576,11 +632,12 @@ class Utils {
|
|
|
576
632
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
577
633
|
};
|
|
578
634
|
const schema = param.schema;
|
|
579
|
-
if (allowMultipleParameters && schema) {
|
|
635
|
+
if (options.allowMultipleParameters && schema) {
|
|
580
636
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
581
637
|
}
|
|
582
638
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
583
639
|
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
640
|
+
parameter.isRequired = true;
|
|
584
641
|
requiredParams.push(parameter);
|
|
585
642
|
}
|
|
586
643
|
else {
|
|
@@ -594,7 +651,7 @@ class Utils {
|
|
|
594
651
|
const requestJson = requestBody.content["application/json"];
|
|
595
652
|
if (Object.keys(requestJson).length !== 0) {
|
|
596
653
|
const schema = requestJson.schema;
|
|
597
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
654
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
598
655
|
requiredParams.push(...requiredP);
|
|
599
656
|
optionalParams.push(...optionalP);
|
|
600
657
|
}
|
|
@@ -625,14 +682,13 @@ class Utils {
|
|
|
625
682
|
}
|
|
626
683
|
return [command, warning];
|
|
627
684
|
}
|
|
628
|
-
static listSupportedAPIs(spec,
|
|
685
|
+
static listSupportedAPIs(spec, options) {
|
|
629
686
|
const paths = spec.paths;
|
|
630
687
|
const result = {};
|
|
631
688
|
for (const path in paths) {
|
|
632
689
|
const methods = paths[path];
|
|
633
690
|
for (const method in methods) {
|
|
634
|
-
|
|
635
|
-
if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
|
|
691
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
636
692
|
const operationObject = methods[method];
|
|
637
693
|
result[`${method.toUpperCase()} ${path}`] = operationObject;
|
|
638
694
|
}
|
|
@@ -640,7 +696,7 @@ class Utils {
|
|
|
640
696
|
}
|
|
641
697
|
return result;
|
|
642
698
|
}
|
|
643
|
-
static validateSpec(spec, parser, isSwaggerFile,
|
|
699
|
+
static validateSpec(spec, parser, isSwaggerFile, options) {
|
|
644
700
|
const errors = [];
|
|
645
701
|
const warnings = [];
|
|
646
702
|
if (isSwaggerFile) {
|
|
@@ -650,7 +706,7 @@ class Utils {
|
|
|
650
706
|
});
|
|
651
707
|
}
|
|
652
708
|
// Server validation
|
|
653
|
-
const serverErrors = Utils.validateServer(spec,
|
|
709
|
+
const serverErrors = Utils.validateServer(spec, options);
|
|
654
710
|
errors.push(...serverErrors);
|
|
655
711
|
// Remote reference not supported
|
|
656
712
|
const refPaths = parser.$refs.paths();
|
|
@@ -663,7 +719,7 @@ class Utils {
|
|
|
663
719
|
});
|
|
664
720
|
}
|
|
665
721
|
// No supported API
|
|
666
|
-
const apiMap = Utils.listSupportedAPIs(spec,
|
|
722
|
+
const apiMap = Utils.listSupportedAPIs(spec, options);
|
|
667
723
|
if (Object.keys(apiMap).length === 0) {
|
|
668
724
|
errors.push({
|
|
669
725
|
type: ErrorType.NoSupportedApi,
|
|
@@ -715,6 +771,19 @@ class Utils {
|
|
|
715
771
|
}
|
|
716
772
|
return safeRegistrationIdEnvName;
|
|
717
773
|
}
|
|
774
|
+
static getAllAPICount(spec) {
|
|
775
|
+
let count = 0;
|
|
776
|
+
const paths = spec.paths;
|
|
777
|
+
for (const path in paths) {
|
|
778
|
+
const methods = paths[path];
|
|
779
|
+
for (const method in methods) {
|
|
780
|
+
if (ConstantString.AllOperationMethods.includes(method)) {
|
|
781
|
+
count++;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
return count;
|
|
786
|
+
}
|
|
718
787
|
}
|
|
719
788
|
|
|
720
789
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -733,7 +802,10 @@ class SpecParser {
|
|
|
733
802
|
allowSwagger: false,
|
|
734
803
|
allowAPIKeyAuth: false,
|
|
735
804
|
allowMultipleParameters: false,
|
|
805
|
+
allowBearerTokenAuth: false,
|
|
736
806
|
allowOauth2: false,
|
|
807
|
+
allowMethods: ["get", "post"],
|
|
808
|
+
projectType: ProjectType.SME,
|
|
737
809
|
};
|
|
738
810
|
this.pathOrSpec = pathOrDoc;
|
|
739
811
|
this.parser = new SwaggerParser();
|
|
@@ -770,7 +842,7 @@ class SpecParser {
|
|
|
770
842
|
],
|
|
771
843
|
};
|
|
772
844
|
}
|
|
773
|
-
return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options
|
|
845
|
+
return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
|
|
774
846
|
}
|
|
775
847
|
catch (err) {
|
|
776
848
|
throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
|
|
@@ -789,7 +861,7 @@ class SpecParser {
|
|
|
789
861
|
if (!operationId) {
|
|
790
862
|
continue;
|
|
791
863
|
}
|
|
792
|
-
const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options
|
|
864
|
+
const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
|
|
793
865
|
const apiInfo = {
|
|
794
866
|
method: method,
|
|
795
867
|
path: path,
|
|
@@ -818,12 +890,32 @@ class SpecParser {
|
|
|
818
890
|
async list() {
|
|
819
891
|
throw new Error("Method not implemented.");
|
|
820
892
|
}
|
|
893
|
+
/**
|
|
894
|
+
* Generate specs according to the filters.
|
|
895
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
896
|
+
*/
|
|
897
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
898
|
+
async getFilteredSpecs(filter, signal) {
|
|
899
|
+
throw new Error("Method not implemented.");
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
903
|
+
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
904
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
905
|
+
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
906
|
+
* @param pluginFilePath File path of the api plugin file to generate.
|
|
907
|
+
*/
|
|
908
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
909
|
+
async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
910
|
+
throw new Error("Method not implemented.");
|
|
911
|
+
}
|
|
821
912
|
/**
|
|
822
913
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
823
914
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
824
915
|
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
825
916
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
826
917
|
* @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
|
|
918
|
+
* @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
|
|
827
919
|
*/
|
|
828
920
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
829
921
|
async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
@@ -843,11 +935,169 @@ class SpecParser {
|
|
|
843
935
|
if (this.apiMap !== undefined) {
|
|
844
936
|
return this.apiMap;
|
|
845
937
|
}
|
|
846
|
-
const result = Utils.listSupportedAPIs(spec, this.options
|
|
938
|
+
const result = Utils.listSupportedAPIs(spec, this.options);
|
|
847
939
|
this.apiMap = result;
|
|
848
940
|
return result;
|
|
849
941
|
}
|
|
850
942
|
}
|
|
851
943
|
|
|
852
|
-
|
|
944
|
+
// Copyright (c) Microsoft Corporation.
|
|
945
|
+
class AdaptiveCardGenerator {
|
|
946
|
+
static generateAdaptiveCard(operationItem) {
|
|
947
|
+
try {
|
|
948
|
+
const json = Utils.getResponseJson(operationItem);
|
|
949
|
+
let cardBody = [];
|
|
950
|
+
let schema = json.schema;
|
|
951
|
+
let jsonPath = "$";
|
|
952
|
+
if (schema && Object.keys(schema).length > 0) {
|
|
953
|
+
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
954
|
+
if (jsonPath !== "$") {
|
|
955
|
+
schema = schema.properties[jsonPath];
|
|
956
|
+
}
|
|
957
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
958
|
+
}
|
|
959
|
+
// if no schema, try to use example value
|
|
960
|
+
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
961
|
+
cardBody = [
|
|
962
|
+
{
|
|
963
|
+
type: ConstantString.TextBlockType,
|
|
964
|
+
text: "${jsonStringify($root)}",
|
|
965
|
+
wrap: true,
|
|
966
|
+
},
|
|
967
|
+
];
|
|
968
|
+
}
|
|
969
|
+
// if no example value, use default success response
|
|
970
|
+
if (cardBody.length === 0) {
|
|
971
|
+
cardBody = [
|
|
972
|
+
{
|
|
973
|
+
type: ConstantString.TextBlockType,
|
|
974
|
+
text: "success",
|
|
975
|
+
wrap: true,
|
|
976
|
+
},
|
|
977
|
+
];
|
|
978
|
+
}
|
|
979
|
+
const fullCard = {
|
|
980
|
+
type: ConstantString.AdaptiveCardType,
|
|
981
|
+
$schema: ConstantString.AdaptiveCardSchema,
|
|
982
|
+
version: ConstantString.AdaptiveCardVersion,
|
|
983
|
+
body: cardBody,
|
|
984
|
+
};
|
|
985
|
+
return [fullCard, jsonPath];
|
|
986
|
+
}
|
|
987
|
+
catch (err) {
|
|
988
|
+
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
992
|
+
if (schema.type === "array") {
|
|
993
|
+
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
994
|
+
if (Object.keys(schema.items).length === 0) {
|
|
995
|
+
return [
|
|
996
|
+
{
|
|
997
|
+
type: ConstantString.TextBlockType,
|
|
998
|
+
text: name ? `${name}: \${jsonStringify(${name})}` : "result: ${jsonStringify($root)}",
|
|
999
|
+
wrap: true,
|
|
1000
|
+
},
|
|
1001
|
+
];
|
|
1002
|
+
}
|
|
1003
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
1004
|
+
const template = {
|
|
1005
|
+
type: ConstantString.ContainerType,
|
|
1006
|
+
$data: name ? `\${${name}}` : "${$root}",
|
|
1007
|
+
items: Array(),
|
|
1008
|
+
};
|
|
1009
|
+
template.items.push(...obj);
|
|
1010
|
+
return [template];
|
|
1011
|
+
}
|
|
1012
|
+
// some schema may not contain type but contain properties
|
|
1013
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
1014
|
+
const { properties } = schema;
|
|
1015
|
+
const result = [];
|
|
1016
|
+
for (const property in properties) {
|
|
1017
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
1018
|
+
result.push(...obj);
|
|
1019
|
+
}
|
|
1020
|
+
if (schema.additionalProperties) {
|
|
1021
|
+
// TODO: better ways to handler warnings.
|
|
1022
|
+
console.warn(ConstantString.AdditionalPropertiesNotSupported);
|
|
1023
|
+
}
|
|
1024
|
+
return result;
|
|
1025
|
+
}
|
|
1026
|
+
if (schema.type === "string" ||
|
|
1027
|
+
schema.type === "integer" ||
|
|
1028
|
+
schema.type === "boolean" ||
|
|
1029
|
+
schema.type === "number") {
|
|
1030
|
+
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1031
|
+
// string in root: "ddd"
|
|
1032
|
+
let text = "result: ${$root}";
|
|
1033
|
+
if (name) {
|
|
1034
|
+
// object { id: "1" }
|
|
1035
|
+
text = `${name}: \${if(${name}, ${name}, 'N/A')}`;
|
|
1036
|
+
if (parentArrayName) {
|
|
1037
|
+
// object types inside array: { tags: ["id": 1, "name": "name"] }
|
|
1038
|
+
text = `${parentArrayName}.${text}`;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
else if (parentArrayName) {
|
|
1042
|
+
// string array: photoUrls: ["1", "2"]
|
|
1043
|
+
text = `${parentArrayName}: ` + "${$data}";
|
|
1044
|
+
}
|
|
1045
|
+
return [
|
|
1046
|
+
{
|
|
1047
|
+
type: ConstantString.TextBlockType,
|
|
1048
|
+
text,
|
|
1049
|
+
wrap: true,
|
|
1050
|
+
},
|
|
1051
|
+
];
|
|
1052
|
+
}
|
|
1053
|
+
else {
|
|
1054
|
+
if (name) {
|
|
1055
|
+
return [
|
|
1056
|
+
{
|
|
1057
|
+
type: "Image",
|
|
1058
|
+
url: `\${${name}}`,
|
|
1059
|
+
$when: `\${${name} != null}`,
|
|
1060
|
+
},
|
|
1061
|
+
];
|
|
1062
|
+
}
|
|
1063
|
+
else {
|
|
1064
|
+
return [
|
|
1065
|
+
{
|
|
1066
|
+
type: "Image",
|
|
1067
|
+
url: "${$data}",
|
|
1068
|
+
$when: "${$data != null}",
|
|
1069
|
+
},
|
|
1070
|
+
];
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
1075
|
+
throw new Error(Utils.format(ConstantString.SchemaNotSupported, JSON.stringify(schema)));
|
|
1076
|
+
}
|
|
1077
|
+
throw new Error(Utils.format(ConstantString.UnknownSchema, JSON.stringify(schema)));
|
|
1078
|
+
}
|
|
1079
|
+
// Find the first array property in the response schema object with the well-known name
|
|
1080
|
+
static getResponseJsonPathFromSchema(schema) {
|
|
1081
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
1082
|
+
const { properties } = schema;
|
|
1083
|
+
for (const property in properties) {
|
|
1084
|
+
const schema = properties[property];
|
|
1085
|
+
if (schema.type === "array" &&
|
|
1086
|
+
Utils.isWellKnownName(property, ConstantString.WellknownResultNames)) {
|
|
1087
|
+
return property;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return "$";
|
|
1092
|
+
}
|
|
1093
|
+
static isImageUrlProperty(schema, name, parentArrayName) {
|
|
1094
|
+
const propertyName = name ? name : parentArrayName;
|
|
1095
|
+
return (!!propertyName &&
|
|
1096
|
+
schema.type === "string" &&
|
|
1097
|
+
Utils.isWellKnownName(propertyName, ConstantString.WellknownImageName) &&
|
|
1098
|
+
(propertyName.toLocaleLowerCase().indexOf("url") >= 0 || schema.format === "uri"));
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
export { AdaptiveCardGenerator, ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|
|
853
1103
|
//# sourceMappingURL=index.esm2017.js.map
|