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