@microsoft/m365-spec-parser 0.1.1-alpha.78701ec6a.0 → 0.1.1-alpha.7fe3da414.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 +449 -125
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +579 -225
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +453 -125
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +585 -224
- 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 +76 -18
- package/dist/src/manifestUpdater.d.ts +9 -4
- package/dist/src/specFilter.d.ts +2 -1
- package/dist/src/specParser.browser.d.ts +16 -1
- package/dist/src/specParser.d.ts +16 -3
- package/dist/src/utils.d.ts +24 -19
- package/package.json +4 -4
package/dist/index.node.cjs.js
CHANGED
|
@@ -61,7 +61,8 @@ exports.ErrorType = void 0;
|
|
|
61
61
|
ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
|
|
62
62
|
ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
|
|
63
63
|
ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
|
|
64
|
-
ErrorType["
|
|
64
|
+
ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
|
|
65
|
+
ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
|
|
65
66
|
ErrorType["ListFailed"] = "list-failed";
|
|
66
67
|
ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
|
|
67
68
|
ErrorType["FilterSpecFailed"] = "filter-spec-failed";
|
|
@@ -69,6 +70,22 @@ exports.ErrorType = void 0;
|
|
|
69
70
|
ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
|
|
70
71
|
ErrorType["GenerateFailed"] = "generate-failed";
|
|
71
72
|
ErrorType["ValidateFailed"] = "validate-failed";
|
|
73
|
+
ErrorType["GetSpecFailed"] = "get-spec-failed";
|
|
74
|
+
ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
|
|
75
|
+
ErrorType["MissingOperationId"] = "missing-operation-id";
|
|
76
|
+
ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
|
|
77
|
+
ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
|
|
78
|
+
ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
|
|
79
|
+
ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
|
|
80
|
+
ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
|
|
81
|
+
ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
|
|
82
|
+
ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
|
|
83
|
+
ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
|
|
84
|
+
ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
|
|
85
|
+
ErrorType["NoParameter"] = "no-parameter";
|
|
86
|
+
ErrorType["NoAPIInfo"] = "no-api-info";
|
|
87
|
+
ErrorType["MethodNotAllowed"] = "method-not-allowed";
|
|
88
|
+
ErrorType["UrlPathNotExist"] = "url-path-not-exist";
|
|
72
89
|
ErrorType["Cancelled"] = "cancelled";
|
|
73
90
|
ErrorType["Unknown"] = "unknown";
|
|
74
91
|
})(exports.ErrorType || (exports.ErrorType = {}));
|
|
@@ -91,7 +108,13 @@ exports.ValidationStatus = void 0;
|
|
|
91
108
|
ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
|
|
92
109
|
ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
|
|
93
110
|
ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
|
|
94
|
-
})(exports.ValidationStatus || (exports.ValidationStatus = {}));
|
|
111
|
+
})(exports.ValidationStatus || (exports.ValidationStatus = {}));
|
|
112
|
+
exports.ProjectType = void 0;
|
|
113
|
+
(function (ProjectType) {
|
|
114
|
+
ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
|
|
115
|
+
ProjectType[ProjectType["SME"] = 1] = "SME";
|
|
116
|
+
ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
|
|
117
|
+
})(exports.ProjectType || (exports.ProjectType = {}));
|
|
95
118
|
|
|
96
119
|
// Copyright (c) Microsoft Corporation.
|
|
97
120
|
class ConstantString {
|
|
@@ -110,7 +133,9 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
|
|
|
110
133
|
ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
|
|
111
134
|
ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
|
|
112
135
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
113
|
-
ConstantString.
|
|
136
|
+
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
137
|
+
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
138
|
+
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
114
139
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
115
140
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
116
141
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
@@ -122,6 +147,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
|
122
147
|
ConstantString.TextBlockType = "TextBlock";
|
|
123
148
|
ConstantString.ContainerType = "Container";
|
|
124
149
|
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
150
|
+
ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
|
|
125
151
|
ConstantString.ResponseCodeFor20X = [
|
|
126
152
|
"200",
|
|
127
153
|
"201",
|
|
@@ -181,7 +207,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
|
|
|
181
207
|
ConstantString.CommandDescriptionMaxLens = 128;
|
|
182
208
|
ConstantString.ParameterDescriptionMaxLens = 128;
|
|
183
209
|
ConstantString.CommandTitleMaxLens = 32;
|
|
184
|
-
ConstantString.ParameterTitleMaxLens = 32;
|
|
210
|
+
ConstantString.ParameterTitleMaxLens = 32;
|
|
211
|
+
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
185
212
|
|
|
186
213
|
// Copyright (c) Microsoft Corporation.
|
|
187
214
|
class SpecParserError extends Error {
|
|
@@ -193,11 +220,23 @@ class SpecParserError extends Error {
|
|
|
193
220
|
|
|
194
221
|
// Copyright (c) Microsoft Corporation.
|
|
195
222
|
class Utils {
|
|
196
|
-
static
|
|
223
|
+
static hasNestedObjectInSchema(schema) {
|
|
224
|
+
if (schema.type === "object") {
|
|
225
|
+
for (const property in schema.properties) {
|
|
226
|
+
const nestedSchema = schema.properties[property];
|
|
227
|
+
if (nestedSchema.type === "object") {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
static checkParameters(paramObject, isCopilot) {
|
|
197
235
|
const paramResult = {
|
|
198
236
|
requiredNum: 0,
|
|
199
237
|
optionalNum: 0,
|
|
200
238
|
isValid: true,
|
|
239
|
+
reason: [],
|
|
201
240
|
};
|
|
202
241
|
if (!paramObject) {
|
|
203
242
|
return paramResult;
|
|
@@ -205,10 +244,25 @@ class Utils {
|
|
|
205
244
|
for (let i = 0; i < paramObject.length; i++) {
|
|
206
245
|
const param = paramObject[i];
|
|
207
246
|
const schema = param.schema;
|
|
247
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
248
|
+
paramResult.isValid = false;
|
|
249
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
208
252
|
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
253
|
+
if (isCopilot) {
|
|
254
|
+
if (isRequiredWithoutDefault) {
|
|
255
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
259
|
+
}
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
209
262
|
if (param.in === "header" || param.in === "cookie") {
|
|
210
263
|
if (isRequiredWithoutDefault) {
|
|
211
264
|
paramResult.isValid = false;
|
|
265
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
212
266
|
}
|
|
213
267
|
continue;
|
|
214
268
|
}
|
|
@@ -218,6 +272,7 @@ class Utils {
|
|
|
218
272
|
schema.type !== "integer") {
|
|
219
273
|
if (isRequiredWithoutDefault) {
|
|
220
274
|
paramResult.isValid = false;
|
|
275
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
221
276
|
}
|
|
222
277
|
continue;
|
|
223
278
|
}
|
|
@@ -232,17 +287,23 @@ class Utils {
|
|
|
232
287
|
}
|
|
233
288
|
return paramResult;
|
|
234
289
|
}
|
|
235
|
-
static checkPostBody(schema, isRequired = false) {
|
|
290
|
+
static checkPostBody(schema, isRequired = false, isCopilot = false) {
|
|
236
291
|
var _a;
|
|
237
292
|
const paramResult = {
|
|
238
293
|
requiredNum: 0,
|
|
239
294
|
optionalNum: 0,
|
|
240
295
|
isValid: true,
|
|
296
|
+
reason: [],
|
|
241
297
|
};
|
|
242
298
|
if (Object.keys(schema).length === 0) {
|
|
243
299
|
return paramResult;
|
|
244
300
|
}
|
|
245
301
|
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
302
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
303
|
+
paramResult.isValid = false;
|
|
304
|
+
paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
|
|
305
|
+
return paramResult;
|
|
306
|
+
}
|
|
246
307
|
if (schema.type === "string" ||
|
|
247
308
|
schema.type === "integer" ||
|
|
248
309
|
schema.type === "boolean" ||
|
|
@@ -261,19 +322,24 @@ class Utils {
|
|
|
261
322
|
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
262
323
|
isRequired = true;
|
|
263
324
|
}
|
|
264
|
-
const result = Utils.checkPostBody(properties[property], isRequired);
|
|
325
|
+
const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
|
|
265
326
|
paramResult.requiredNum += result.requiredNum;
|
|
266
327
|
paramResult.optionalNum += result.optionalNum;
|
|
267
328
|
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
329
|
+
paramResult.reason.push(...result.reason);
|
|
268
330
|
}
|
|
269
331
|
}
|
|
270
332
|
else {
|
|
271
|
-
if (isRequiredWithoutDefault) {
|
|
333
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
272
334
|
paramResult.isValid = false;
|
|
335
|
+
paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
273
336
|
}
|
|
274
337
|
}
|
|
275
338
|
return paramResult;
|
|
276
339
|
}
|
|
340
|
+
static containMultipleMediaTypes(bodyObject) {
|
|
341
|
+
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
342
|
+
}
|
|
277
343
|
/**
|
|
278
344
|
* Checks if the given API is supported.
|
|
279
345
|
* @param {string} method - The HTTP method of the API.
|
|
@@ -288,106 +354,137 @@ class Utils {
|
|
|
288
354
|
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
289
355
|
* 6. only support request body with “application/json” content type
|
|
290
356
|
*/
|
|
291
|
-
static isSupportedApi(method, path, spec,
|
|
292
|
-
|
|
357
|
+
static isSupportedApi(method, path, spec, options) {
|
|
358
|
+
var _a;
|
|
359
|
+
const result = { isValid: true, reason: [] };
|
|
293
360
|
method = method.toLocaleLowerCase();
|
|
294
|
-
if (
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
361
|
+
if (options.allowMethods && !options.allowMethods.includes(method)) {
|
|
362
|
+
result.isValid = false;
|
|
363
|
+
result.reason.push(exports.ErrorType.MethodNotAllowed);
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
const pathObj = spec.paths[path];
|
|
367
|
+
if (!pathObj || !pathObj[method]) {
|
|
368
|
+
result.isValid = false;
|
|
369
|
+
result.reason.push(exports.ErrorType.UrlPathNotExist);
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
const securities = pathObj[method].security;
|
|
373
|
+
const isTeamsAi = options.projectType === exports.ProjectType.TeamsAi;
|
|
374
|
+
const isCopilot = options.projectType === exports.ProjectType.Copilot;
|
|
375
|
+
// Teams AI project doesn't care about auth, it will use authProvider for user to implement
|
|
376
|
+
if (!isTeamsAi) {
|
|
377
|
+
const authArray = Utils.getAuthArray(securities, spec);
|
|
378
|
+
const authCheckResult = Utils.isSupportedAuth(authArray, options);
|
|
379
|
+
if (!authCheckResult.isValid) {
|
|
380
|
+
result.reason.push(...authCheckResult.reason);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const operationObject = pathObj[method];
|
|
384
|
+
if (!options.allowMissingId && !operationObject.operationId) {
|
|
385
|
+
result.reason.push(exports.ErrorType.MissingOperationId);
|
|
386
|
+
}
|
|
387
|
+
const rootServer = spec.servers && spec.servers[0];
|
|
388
|
+
const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
|
|
389
|
+
const operationServer = operationObject.servers && operationObject.servers[0];
|
|
390
|
+
const serverUrl = operationServer || methodServer || rootServer;
|
|
391
|
+
if (!serverUrl) {
|
|
392
|
+
result.reason.push(exports.ErrorType.NoServerInformation);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
const serverValidateResult = Utils.checkServerUrl([serverUrl]);
|
|
396
|
+
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
397
|
+
}
|
|
398
|
+
const paramObject = operationObject.parameters;
|
|
399
|
+
const requestBody = operationObject.requestBody;
|
|
400
|
+
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
401
|
+
if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
|
|
402
|
+
result.reason.push(exports.ErrorType.PostBodyContainMultipleMediaTypes);
|
|
403
|
+
}
|
|
404
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject, isTeamsAi);
|
|
405
|
+
if (multipleMediaType && !isTeamsAi) {
|
|
406
|
+
result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
|
|
407
|
+
}
|
|
408
|
+
else if (Object.keys(json).length === 0) {
|
|
409
|
+
result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
|
|
410
|
+
}
|
|
411
|
+
// Teams AI project doesn't care about request parameters/body
|
|
412
|
+
if (!isTeamsAi) {
|
|
413
|
+
let requestBodyParamResult = {
|
|
414
|
+
requiredNum: 0,
|
|
415
|
+
optionalNum: 0,
|
|
416
|
+
isValid: true,
|
|
417
|
+
reason: [],
|
|
418
|
+
};
|
|
419
|
+
if (requestJsonBody) {
|
|
420
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
421
|
+
if (isCopilot && requestBodySchema.type !== "object") {
|
|
422
|
+
result.reason.push(exports.ErrorType.PostBodySchemaIsNotJson);
|
|
328
423
|
}
|
|
329
|
-
|
|
330
|
-
if (!
|
|
331
|
-
|
|
424
|
+
requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
|
|
425
|
+
if (!requestBodyParamResult.isValid && requestBodyParamResult.reason) {
|
|
426
|
+
result.reason.push(...requestBodyParamResult.reason);
|
|
332
427
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
428
|
+
}
|
|
429
|
+
const paramResult = Utils.checkParameters(paramObject, isCopilot);
|
|
430
|
+
if (!paramResult.isValid && paramResult.reason) {
|
|
431
|
+
result.reason.push(...paramResult.reason);
|
|
432
|
+
}
|
|
433
|
+
// Copilot support arbitrary parameters
|
|
434
|
+
if (!isCopilot && paramResult.isValid && requestBodyParamResult.isValid) {
|
|
435
|
+
const totalRequiredParams = requestBodyParamResult.requiredNum + paramResult.requiredNum;
|
|
436
|
+
const totalParams = totalRequiredParams + requestBodyParamResult.optionalNum + paramResult.optionalNum;
|
|
437
|
+
if (totalRequiredParams > 1) {
|
|
438
|
+
if (!options.allowMultipleParameters ||
|
|
439
|
+
totalRequiredParams > ConstantString.SMERequiredParamsMaxNum) {
|
|
440
|
+
result.reason.push(exports.ErrorType.ExceededRequiredParamsLimit);
|
|
337
441
|
}
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
else if (requestBodyParamResult.requiredNum +
|
|
341
|
-
requestBodyParamResult.optionalNum +
|
|
342
|
-
paramResult.requiredNum +
|
|
343
|
-
paramResult.optionalNum ===
|
|
344
|
-
0) {
|
|
345
|
-
return false;
|
|
346
442
|
}
|
|
347
|
-
else {
|
|
348
|
-
|
|
443
|
+
else if (totalParams === 0) {
|
|
444
|
+
result.reason.push(exports.ErrorType.NoParameter);
|
|
349
445
|
}
|
|
350
446
|
}
|
|
351
447
|
}
|
|
352
|
-
|
|
448
|
+
if (result.reason.length > 0) {
|
|
449
|
+
result.isValid = false;
|
|
450
|
+
}
|
|
451
|
+
return result;
|
|
353
452
|
}
|
|
354
|
-
static isSupportedAuth(
|
|
355
|
-
if (
|
|
356
|
-
return true;
|
|
453
|
+
static isSupportedAuth(authSchemeArray, options) {
|
|
454
|
+
if (authSchemeArray.length === 0) {
|
|
455
|
+
return { isValid: true, reason: [] };
|
|
357
456
|
}
|
|
358
|
-
if (allowAPIKeyAuth || allowOauth2) {
|
|
457
|
+
if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
|
|
359
458
|
// Currently we don't support multiple auth in one operation
|
|
360
|
-
if (
|
|
361
|
-
return
|
|
459
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
460
|
+
return {
|
|
461
|
+
isValid: false,
|
|
462
|
+
reason: [exports.ErrorType.MultipleAuthNotSupported],
|
|
463
|
+
};
|
|
362
464
|
}
|
|
363
|
-
for (const auths of
|
|
465
|
+
for (const auths of authSchemeArray) {
|
|
364
466
|
if (auths.length === 1) {
|
|
365
|
-
if (
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
allowOauth2 &&
|
|
370
|
-
Utils.isBearerTokenAuth(auths[0].authSchema)) {
|
|
371
|
-
return true;
|
|
372
|
-
}
|
|
373
|
-
else if (allowAPIKeyAuth &&
|
|
374
|
-
allowOauth2 &&
|
|
375
|
-
(Utils.isAPIKeyAuth(auths[0].authSchema) ||
|
|
376
|
-
Utils.isBearerTokenAuth(auths[0].authSchema))) {
|
|
377
|
-
return true;
|
|
467
|
+
if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
468
|
+
(options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
|
|
469
|
+
(options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
|
|
470
|
+
return { isValid: true, reason: [] };
|
|
378
471
|
}
|
|
379
472
|
}
|
|
380
473
|
}
|
|
381
474
|
}
|
|
382
|
-
return false;
|
|
475
|
+
return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
|
|
383
476
|
}
|
|
384
|
-
static
|
|
385
|
-
return
|
|
477
|
+
static isBearerTokenAuth(authScheme) {
|
|
478
|
+
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
386
479
|
}
|
|
387
|
-
static
|
|
388
|
-
return
|
|
389
|
-
|
|
390
|
-
|
|
480
|
+
static isAPIKeyAuth(authScheme) {
|
|
481
|
+
return authScheme.type === "apiKey";
|
|
482
|
+
}
|
|
483
|
+
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
484
|
+
if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
|
|
485
|
+
return true;
|
|
486
|
+
}
|
|
487
|
+
return false;
|
|
391
488
|
}
|
|
392
489
|
static getAuthArray(securities, spec) {
|
|
393
490
|
var _a;
|
|
@@ -400,7 +497,7 @@ class Utils {
|
|
|
400
497
|
for (const name in security) {
|
|
401
498
|
const auth = securitySchemas[name];
|
|
402
499
|
authArray.push({
|
|
403
|
-
|
|
500
|
+
authScheme: auth,
|
|
404
501
|
name: name,
|
|
405
502
|
});
|
|
406
503
|
}
|
|
@@ -415,21 +512,28 @@ class Utils {
|
|
|
415
512
|
static updateFirstLetter(str) {
|
|
416
513
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
417
514
|
}
|
|
418
|
-
static getResponseJson(operationObject) {
|
|
515
|
+
static getResponseJson(operationObject, isTeamsAiProject = false) {
|
|
419
516
|
var _a, _b;
|
|
420
517
|
let json = {};
|
|
518
|
+
let multipleMediaType = false;
|
|
421
519
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
422
520
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
423
|
-
const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
|
|
424
|
-
if (mediaTypesCount > 1) {
|
|
425
|
-
return {};
|
|
426
|
-
}
|
|
427
521
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
522
|
+
multipleMediaType = false;
|
|
428
523
|
json = responseObject.content["application/json"];
|
|
429
|
-
|
|
524
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
525
|
+
multipleMediaType = true;
|
|
526
|
+
if (isTeamsAiProject) {
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
json = {};
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
430
534
|
}
|
|
431
535
|
}
|
|
432
|
-
return json;
|
|
536
|
+
return { json, multipleMediaType };
|
|
433
537
|
}
|
|
434
538
|
static convertPathToCamelCase(path) {
|
|
435
539
|
const pathSegments = path.split(/[./{]/);
|
|
@@ -449,10 +553,10 @@ class Utils {
|
|
|
449
553
|
return undefined;
|
|
450
554
|
}
|
|
451
555
|
}
|
|
452
|
-
static
|
|
556
|
+
static resolveEnv(str) {
|
|
453
557
|
const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
|
|
454
|
-
let matches = placeHolderReg.exec(
|
|
455
|
-
let
|
|
558
|
+
let matches = placeHolderReg.exec(str);
|
|
559
|
+
let newStr = str;
|
|
456
560
|
while (matches != null) {
|
|
457
561
|
const envVar = matches[1];
|
|
458
562
|
const envVal = process.env[envVar];
|
|
@@ -460,17 +564,17 @@ class Utils {
|
|
|
460
564
|
throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
|
|
461
565
|
}
|
|
462
566
|
else {
|
|
463
|
-
|
|
567
|
+
newStr = newStr.replace(matches[0], envVal);
|
|
464
568
|
}
|
|
465
|
-
matches = placeHolderReg.exec(
|
|
569
|
+
matches = placeHolderReg.exec(str);
|
|
466
570
|
}
|
|
467
|
-
return
|
|
571
|
+
return newStr;
|
|
468
572
|
}
|
|
469
573
|
static checkServerUrl(servers) {
|
|
470
574
|
const errors = [];
|
|
471
575
|
let serverUrl;
|
|
472
576
|
try {
|
|
473
|
-
serverUrl = Utils.
|
|
577
|
+
serverUrl = Utils.resolveEnv(servers[0].url);
|
|
474
578
|
}
|
|
475
579
|
catch (err) {
|
|
476
580
|
errors.push({
|
|
@@ -500,7 +604,8 @@ class Utils {
|
|
|
500
604
|
}
|
|
501
605
|
return errors;
|
|
502
606
|
}
|
|
503
|
-
static validateServer(spec,
|
|
607
|
+
static validateServer(spec, options) {
|
|
608
|
+
var _a;
|
|
504
609
|
const errors = [];
|
|
505
610
|
let hasTopLevelServers = false;
|
|
506
611
|
let hasPathLevelServers = false;
|
|
@@ -521,7 +626,7 @@ class Utils {
|
|
|
521
626
|
}
|
|
522
627
|
for (const method in methods) {
|
|
523
628
|
const operationObject = methods[method];
|
|
524
|
-
if (
|
|
629
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
525
630
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
526
631
|
hasOperationLevelServers = true;
|
|
527
632
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -564,6 +669,7 @@ class Utils {
|
|
|
564
669
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
565
670
|
}
|
|
566
671
|
if (isRequired && schema.default === undefined) {
|
|
672
|
+
parameter.isRequired = true;
|
|
567
673
|
requiredParams.push(parameter);
|
|
568
674
|
}
|
|
569
675
|
else {
|
|
@@ -608,7 +714,7 @@ class Utils {
|
|
|
608
714
|
param.value = schema.default;
|
|
609
715
|
}
|
|
610
716
|
}
|
|
611
|
-
static parseApiInfo(operationItem,
|
|
717
|
+
static parseApiInfo(operationItem, options) {
|
|
612
718
|
var _a, _b;
|
|
613
719
|
const requiredParams = [];
|
|
614
720
|
const optionalParams = [];
|
|
@@ -622,11 +728,12 @@ class Utils {
|
|
|
622
728
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
623
729
|
};
|
|
624
730
|
const schema = param.schema;
|
|
625
|
-
if (allowMultipleParameters && schema) {
|
|
731
|
+
if (options.allowMultipleParameters && schema) {
|
|
626
732
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
627
733
|
}
|
|
628
734
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
629
735
|
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
736
|
+
parameter.isRequired = true;
|
|
630
737
|
requiredParams.push(parameter);
|
|
631
738
|
}
|
|
632
739
|
else {
|
|
@@ -640,7 +747,7 @@ class Utils {
|
|
|
640
747
|
const requestJson = requestBody.content["application/json"];
|
|
641
748
|
if (Object.keys(requestJson).length !== 0) {
|
|
642
749
|
const schema = requestJson.schema;
|
|
643
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
750
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
644
751
|
requiredParams.push(...requiredP);
|
|
645
752
|
optionalParams.push(...optionalP);
|
|
646
753
|
}
|
|
@@ -671,32 +778,37 @@ class Utils {
|
|
|
671
778
|
}
|
|
672
779
|
return [command, warning];
|
|
673
780
|
}
|
|
674
|
-
static
|
|
781
|
+
static listAPIs(spec, options) {
|
|
782
|
+
var _a;
|
|
675
783
|
const paths = spec.paths;
|
|
676
784
|
const result = {};
|
|
677
785
|
for (const path in paths) {
|
|
678
786
|
const methods = paths[path];
|
|
679
787
|
for (const method in methods) {
|
|
680
|
-
|
|
681
|
-
if (
|
|
682
|
-
const
|
|
683
|
-
result[`${method.toUpperCase()} ${path}`] =
|
|
788
|
+
const operationObject = methods[method];
|
|
789
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
790
|
+
const validateResult = Utils.isSupportedApi(method, path, spec, options);
|
|
791
|
+
result[`${method.toUpperCase()} ${path}`] = {
|
|
792
|
+
operation: operationObject,
|
|
793
|
+
isValid: validateResult.isValid,
|
|
794
|
+
reason: validateResult.reason,
|
|
795
|
+
};
|
|
684
796
|
}
|
|
685
797
|
}
|
|
686
798
|
}
|
|
687
799
|
return result;
|
|
688
800
|
}
|
|
689
|
-
static validateSpec(spec, parser, isSwaggerFile,
|
|
801
|
+
static validateSpec(spec, parser, isSwaggerFile, options) {
|
|
690
802
|
const errors = [];
|
|
691
803
|
const warnings = [];
|
|
804
|
+
const apiMap = Utils.listAPIs(spec, options);
|
|
692
805
|
if (isSwaggerFile) {
|
|
693
806
|
warnings.push({
|
|
694
807
|
type: exports.WarningType.ConvertSwaggerToOpenAPI,
|
|
695
808
|
content: ConstantString.ConvertSwaggerToOpenAPI,
|
|
696
809
|
});
|
|
697
810
|
}
|
|
698
|
-
|
|
699
|
-
const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
|
|
811
|
+
const serverErrors = Utils.validateServer(spec, options);
|
|
700
812
|
errors.push(...serverErrors);
|
|
701
813
|
// Remote reference not supported
|
|
702
814
|
const refPaths = parser.$refs.paths();
|
|
@@ -709,8 +821,8 @@ class Utils {
|
|
|
709
821
|
});
|
|
710
822
|
}
|
|
711
823
|
// No supported API
|
|
712
|
-
const
|
|
713
|
-
if (
|
|
824
|
+
const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
|
|
825
|
+
if (validAPIs.length === 0) {
|
|
714
826
|
errors.push({
|
|
715
827
|
type: exports.ErrorType.NoSupportedApi,
|
|
716
828
|
content: ConstantString.NoSupportedApi,
|
|
@@ -719,8 +831,8 @@ class Utils {
|
|
|
719
831
|
// OperationId missing
|
|
720
832
|
const apisMissingOperationId = [];
|
|
721
833
|
for (const key in apiMap) {
|
|
722
|
-
const
|
|
723
|
-
if (!
|
|
834
|
+
const { operation } = apiMap[key];
|
|
835
|
+
if (!operation.operationId) {
|
|
724
836
|
apisMissingOperationId.push(key);
|
|
725
837
|
}
|
|
726
838
|
}
|
|
@@ -761,30 +873,50 @@ class Utils {
|
|
|
761
873
|
}
|
|
762
874
|
return safeRegistrationIdEnvName;
|
|
763
875
|
}
|
|
876
|
+
static getAllAPICount(spec) {
|
|
877
|
+
let count = 0;
|
|
878
|
+
const paths = spec.paths;
|
|
879
|
+
for (const path in paths) {
|
|
880
|
+
const methods = paths[path];
|
|
881
|
+
for (const method in methods) {
|
|
882
|
+
if (ConstantString.AllOperationMethods.includes(method)) {
|
|
883
|
+
count++;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return count;
|
|
888
|
+
}
|
|
764
889
|
}
|
|
765
890
|
|
|
766
891
|
// Copyright (c) Microsoft Corporation.
|
|
767
892
|
class SpecFilter {
|
|
768
|
-
static specFilter(filter, unResolveSpec, resolvedSpec,
|
|
893
|
+
static specFilter(filter, unResolveSpec, resolvedSpec, options) {
|
|
894
|
+
var _a;
|
|
769
895
|
try {
|
|
770
896
|
const newSpec = Object.assign({}, unResolveSpec);
|
|
771
897
|
const newPaths = {};
|
|
772
898
|
for (const filterItem of filter) {
|
|
773
899
|
const [method, path] = filterItem.split(" ");
|
|
774
900
|
const methodName = method.toLowerCase();
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
901
|
+
const pathObj = (_a = resolvedSpec.paths) === null || _a === void 0 ? void 0 : _a[path];
|
|
902
|
+
if (ConstantString.AllOperationMethods.includes(methodName) &&
|
|
903
|
+
pathObj &&
|
|
904
|
+
pathObj[methodName]) {
|
|
905
|
+
const validateResult = Utils.isSupportedApi(methodName, path, resolvedSpec, options);
|
|
906
|
+
if (!validateResult.isValid) {
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
if (!newPaths[path]) {
|
|
910
|
+
newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
|
|
911
|
+
for (const m of ConstantString.AllOperationMethods) {
|
|
912
|
+
delete newPaths[path][m];
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
|
|
916
|
+
// Add the operationId if missing
|
|
917
|
+
if (!newPaths[path][methodName].operationId) {
|
|
918
|
+
newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
|
|
782
919
|
}
|
|
783
|
-
}
|
|
784
|
-
newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
|
|
785
|
-
// Add the operationId if missing
|
|
786
|
-
if (!newPaths[path][methodName].operationId) {
|
|
787
|
-
newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
|
|
788
920
|
}
|
|
789
921
|
}
|
|
790
922
|
newSpec.paths = newPaths;
|
|
@@ -798,47 +930,171 @@ class SpecFilter {
|
|
|
798
930
|
|
|
799
931
|
// Copyright (c) Microsoft Corporation.
|
|
800
932
|
class ManifestUpdater {
|
|
801
|
-
static
|
|
933
|
+
static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
|
|
934
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
935
|
+
const manifest = yield fs__default['default'].readJSON(manifestPath);
|
|
936
|
+
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
937
|
+
manifest.plugins = [
|
|
938
|
+
{
|
|
939
|
+
pluginFile: apiPluginRelativePath,
|
|
940
|
+
},
|
|
941
|
+
];
|
|
942
|
+
const appName = this.removeEnvs(manifest.name.short);
|
|
943
|
+
ManifestUpdater.updateManifestDescription(manifest, spec);
|
|
944
|
+
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
945
|
+
const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
|
|
946
|
+
return [manifest, apiPlugin];
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
static updateManifestDescription(manifest, spec) {
|
|
802
950
|
var _a, _b;
|
|
951
|
+
manifest.description = {
|
|
952
|
+
short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
|
|
953
|
+
full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : manifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
|
|
957
|
+
let parameter;
|
|
958
|
+
if (schema.type === "string" ||
|
|
959
|
+
schema.type === "boolean" ||
|
|
960
|
+
schema.type === "integer" ||
|
|
961
|
+
schema.type === "number" ||
|
|
962
|
+
schema.type === "array") {
|
|
963
|
+
parameter = schema;
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), exports.ErrorType.UpdateManifestFailed);
|
|
967
|
+
}
|
|
968
|
+
return parameter;
|
|
969
|
+
}
|
|
970
|
+
static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
|
|
971
|
+
var _a, _b, _c;
|
|
972
|
+
const functions = [];
|
|
973
|
+
const functionNames = [];
|
|
974
|
+
const paths = spec.paths;
|
|
975
|
+
for (const pathUrl in paths) {
|
|
976
|
+
const pathItem = paths[pathUrl];
|
|
977
|
+
if (pathItem) {
|
|
978
|
+
const operations = pathItem;
|
|
979
|
+
for (const method in operations) {
|
|
980
|
+
if (options.allowMethods.includes(method)) {
|
|
981
|
+
const operationItem = operations[method];
|
|
982
|
+
if (operationItem) {
|
|
983
|
+
const operationId = operationItem.operationId;
|
|
984
|
+
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
985
|
+
const paramObject = operationItem.parameters;
|
|
986
|
+
const requestBody = operationItem.requestBody;
|
|
987
|
+
const parameters = {
|
|
988
|
+
type: "object",
|
|
989
|
+
properties: {},
|
|
990
|
+
required: [],
|
|
991
|
+
};
|
|
992
|
+
if (paramObject) {
|
|
993
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
994
|
+
const param = paramObject[i];
|
|
995
|
+
const schema = param.schema;
|
|
996
|
+
parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
|
|
997
|
+
if (param.required) {
|
|
998
|
+
parameters.required.push(param.name);
|
|
999
|
+
}
|
|
1000
|
+
if (!parameters.properties[param.name].description) {
|
|
1001
|
+
parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
if (requestBody) {
|
|
1006
|
+
const requestJsonBody = requestBody.content["application/json"];
|
|
1007
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
1008
|
+
if (requestBodySchema.type === "object") {
|
|
1009
|
+
if (requestBodySchema.required) {
|
|
1010
|
+
parameters.required.push(...requestBodySchema.required);
|
|
1011
|
+
}
|
|
1012
|
+
for (const property in requestBodySchema.properties) {
|
|
1013
|
+
const schema = requestBodySchema.properties[property];
|
|
1014
|
+
parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
else {
|
|
1018
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
const funcObj = {
|
|
1022
|
+
name: operationId,
|
|
1023
|
+
description: description,
|
|
1024
|
+
parameters: parameters,
|
|
1025
|
+
};
|
|
1026
|
+
functions.push(funcObj);
|
|
1027
|
+
functionNames.push(operationId);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
const apiPlugin = {
|
|
1034
|
+
schema_version: "v2",
|
|
1035
|
+
name_for_human: appName,
|
|
1036
|
+
description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
|
|
1037
|
+
functions: functions,
|
|
1038
|
+
runtimes: [
|
|
1039
|
+
{
|
|
1040
|
+
type: "OpenApi",
|
|
1041
|
+
auth: {
|
|
1042
|
+
type: "none", // TODO, support auth in the future
|
|
1043
|
+
},
|
|
1044
|
+
spec: {
|
|
1045
|
+
url: specRelativePath,
|
|
1046
|
+
},
|
|
1047
|
+
run_for_functions: functionNames,
|
|
1048
|
+
},
|
|
1049
|
+
],
|
|
1050
|
+
};
|
|
1051
|
+
return apiPlugin;
|
|
1052
|
+
}
|
|
1053
|
+
static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
|
|
803
1054
|
return __awaiter(this, void 0, void 0, function* () {
|
|
804
1055
|
try {
|
|
805
1056
|
const originalManifest = yield fs__default['default'].readJSON(manifestPath);
|
|
806
1057
|
const updatedPart = {};
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
commands
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1058
|
+
updatedPart.composeExtensions = [];
|
|
1059
|
+
let warnings = [];
|
|
1060
|
+
if (options.projectType === exports.ProjectType.SME) {
|
|
1061
|
+
const updateResult = yield ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
|
|
1062
|
+
const commands = updateResult[0];
|
|
1063
|
+
warnings = updateResult[1];
|
|
1064
|
+
const composeExtension = {
|
|
1065
|
+
composeExtensionType: "apiBased",
|
|
1066
|
+
apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
|
|
1067
|
+
commands: commands,
|
|
1068
|
+
};
|
|
1069
|
+
if (authInfo) {
|
|
1070
|
+
const auth = authInfo.authScheme;
|
|
1071
|
+
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1072
|
+
const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
1073
|
+
composeExtension.authorization = {
|
|
1074
|
+
authType: "apiSecretServiceAuth",
|
|
1075
|
+
apiSecretServiceAuthConfiguration: {
|
|
1076
|
+
apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
|
|
1077
|
+
},
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
|
|
1081
|
+
const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
|
|
1082
|
+
composeExtension.authorization = {
|
|
1083
|
+
authType: "oAuth2.0",
|
|
1084
|
+
oAuthConfiguration: {
|
|
1085
|
+
oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
|
|
1086
|
+
},
|
|
1087
|
+
};
|
|
1088
|
+
updatedPart.webApplicationInfo = {
|
|
1089
|
+
id: "${{AAD_APP_CLIENT_ID}}",
|
|
1090
|
+
resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
835
1093
|
}
|
|
1094
|
+
updatedPart.composeExtensions = [composeExtension];
|
|
836
1095
|
}
|
|
837
|
-
updatedPart.description =
|
|
838
|
-
|
|
839
|
-
full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : originalManifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
|
|
840
|
-
};
|
|
841
|
-
updatedPart.composeExtensions = [composeExtension];
|
|
1096
|
+
updatedPart.description = originalManifest.description;
|
|
1097
|
+
ManifestUpdater.updateManifestDescription(updatedPart, spec);
|
|
842
1098
|
const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
|
|
843
1099
|
return [updatedManifest, warnings];
|
|
844
1100
|
}
|
|
@@ -847,7 +1103,8 @@ class ManifestUpdater {
|
|
|
847
1103
|
}
|
|
848
1104
|
});
|
|
849
1105
|
}
|
|
850
|
-
static generateCommands(spec,
|
|
1106
|
+
static generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
|
|
1107
|
+
var _a;
|
|
851
1108
|
return __awaiter(this, void 0, void 0, function* () {
|
|
852
1109
|
const paths = spec.paths;
|
|
853
1110
|
const commands = [];
|
|
@@ -859,14 +1116,16 @@ class ManifestUpdater {
|
|
|
859
1116
|
const operations = pathItem;
|
|
860
1117
|
// Currently only support GET and POST method
|
|
861
1118
|
for (const method in operations) {
|
|
862
|
-
if (
|
|
1119
|
+
if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
|
|
863
1120
|
const operationItem = operations[method];
|
|
864
1121
|
if (operationItem) {
|
|
865
|
-
const [command, warning] = Utils.parseApiInfo(operationItem,
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1122
|
+
const [command, warning] = Utils.parseApiInfo(operationItem, options);
|
|
1123
|
+
if (adaptiveCardFolder) {
|
|
1124
|
+
const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
|
|
1125
|
+
command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
|
|
1126
|
+
? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
|
|
1127
|
+
: "";
|
|
1128
|
+
}
|
|
870
1129
|
if (warning) {
|
|
871
1130
|
warnings.push(warning);
|
|
872
1131
|
}
|
|
@@ -884,13 +1143,22 @@ class ManifestUpdater {
|
|
|
884
1143
|
const relativePath = path__default['default'].relative(path__default['default'].dirname(from), to);
|
|
885
1144
|
return path__default['default'].normalize(relativePath).replace(/\\/g, "/");
|
|
886
1145
|
}
|
|
1146
|
+
static removeEnvs(str) {
|
|
1147
|
+
const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
|
|
1148
|
+
const matches = placeHolderReg.exec(str);
|
|
1149
|
+
let newStr = str;
|
|
1150
|
+
if (matches != null) {
|
|
1151
|
+
newStr = newStr.replace(matches[0], "");
|
|
1152
|
+
}
|
|
1153
|
+
return newStr;
|
|
1154
|
+
}
|
|
887
1155
|
}
|
|
888
1156
|
|
|
889
1157
|
// Copyright (c) Microsoft Corporation.
|
|
890
1158
|
class AdaptiveCardGenerator {
|
|
891
1159
|
static generateAdaptiveCard(operationItem) {
|
|
892
1160
|
try {
|
|
893
|
-
const json = Utils.getResponseJson(operationItem);
|
|
1161
|
+
const { json } = Utils.getResponseJson(operationItem);
|
|
894
1162
|
let cardBody = [];
|
|
895
1163
|
let schema = json.schema;
|
|
896
1164
|
let jsonPath = "$";
|
|
@@ -1150,8 +1418,11 @@ class SpecParser {
|
|
|
1150
1418
|
allowMissingId: true,
|
|
1151
1419
|
allowSwagger: true,
|
|
1152
1420
|
allowAPIKeyAuth: false,
|
|
1421
|
+
allowBearerTokenAuth: false,
|
|
1153
1422
|
allowMultipleParameters: false,
|
|
1154
1423
|
allowOauth2: false,
|
|
1424
|
+
allowMethods: ["get", "post"],
|
|
1425
|
+
projectType: exports.ProjectType.SME,
|
|
1155
1426
|
};
|
|
1156
1427
|
this.pathOrSpec = pathOrDoc;
|
|
1157
1428
|
this.parser = new SwaggerParser__default['default']();
|
|
@@ -1185,7 +1456,23 @@ class SpecParser {
|
|
|
1185
1456
|
],
|
|
1186
1457
|
};
|
|
1187
1458
|
}
|
|
1188
|
-
|
|
1459
|
+
if (this.options.projectType === exports.ProjectType.SME ||
|
|
1460
|
+
this.options.projectType === exports.ProjectType.Copilot) {
|
|
1461
|
+
if (this.spec.openapi >= "3.1.0") {
|
|
1462
|
+
return {
|
|
1463
|
+
status: exports.ValidationStatus.Error,
|
|
1464
|
+
warnings: [],
|
|
1465
|
+
errors: [
|
|
1466
|
+
{
|
|
1467
|
+
type: exports.ErrorType.SpecVersionNotSupported,
|
|
1468
|
+
content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
|
|
1469
|
+
data: this.spec.openapi,
|
|
1470
|
+
},
|
|
1471
|
+
],
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
|
|
1189
1476
|
}
|
|
1190
1477
|
catch (err) {
|
|
1191
1478
|
throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
|
|
@@ -1209,16 +1496,22 @@ class SpecParser {
|
|
|
1209
1496
|
try {
|
|
1210
1497
|
yield this.loadSpec();
|
|
1211
1498
|
const spec = this.spec;
|
|
1212
|
-
const apiMap = this.
|
|
1213
|
-
const result =
|
|
1499
|
+
const apiMap = this.getAPIs(spec);
|
|
1500
|
+
const result = {
|
|
1501
|
+
APIs: [],
|
|
1502
|
+
allAPICount: 0,
|
|
1503
|
+
validAPICount: 0,
|
|
1504
|
+
};
|
|
1214
1505
|
for (const apiKey in apiMap) {
|
|
1506
|
+
const { operation, isValid, reason } = apiMap[apiKey];
|
|
1507
|
+
const [method, path] = apiKey.split(" ");
|
|
1215
1508
|
const apiResult = {
|
|
1216
1509
|
api: "",
|
|
1217
1510
|
server: "",
|
|
1218
1511
|
operationId: "",
|
|
1512
|
+
isValid: isValid,
|
|
1513
|
+
reason: reason,
|
|
1219
1514
|
};
|
|
1220
|
-
const [method, path] = apiKey.split(" ");
|
|
1221
|
-
const operation = apiMap[apiKey];
|
|
1222
1515
|
const rootServer = spec.servers && spec.servers[0];
|
|
1223
1516
|
const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
|
|
1224
1517
|
const operationServer = operation.servers && operation.servers[0];
|
|
@@ -1226,7 +1519,7 @@ class SpecParser {
|
|
|
1226
1519
|
if (!serverUrl) {
|
|
1227
1520
|
throw new SpecParserError(ConstantString.NoServerInformation, exports.ErrorType.NoServerInformation);
|
|
1228
1521
|
}
|
|
1229
|
-
apiResult.server = Utils.
|
|
1522
|
+
apiResult.server = Utils.resolveEnv(serverUrl.url);
|
|
1230
1523
|
let operationId = operation.operationId;
|
|
1231
1524
|
if (!operationId) {
|
|
1232
1525
|
operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
|
|
@@ -1235,13 +1528,15 @@ class SpecParser {
|
|
|
1235
1528
|
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1236
1529
|
for (const auths of authArray) {
|
|
1237
1530
|
if (auths.length === 1) {
|
|
1238
|
-
apiResult.auth = auths[0]
|
|
1531
|
+
apiResult.auth = auths[0];
|
|
1239
1532
|
break;
|
|
1240
1533
|
}
|
|
1241
1534
|
}
|
|
1242
1535
|
apiResult.api = apiKey;
|
|
1243
|
-
result.push(apiResult);
|
|
1536
|
+
result.APIs.push(apiResult);
|
|
1244
1537
|
}
|
|
1538
|
+
result.allAPICount = result.APIs.length;
|
|
1539
|
+
result.validAPICount = result.APIs.filter((api) => api.isValid).length;
|
|
1245
1540
|
return result;
|
|
1246
1541
|
}
|
|
1247
1542
|
catch (err) {
|
|
@@ -1252,49 +1547,113 @@ class SpecParser {
|
|
|
1252
1547
|
}
|
|
1253
1548
|
});
|
|
1254
1549
|
}
|
|
1550
|
+
/**
|
|
1551
|
+
* Generate specs according to the filters.
|
|
1552
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1553
|
+
*/
|
|
1554
|
+
getFilteredSpecs(filter, signal) {
|
|
1555
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1556
|
+
try {
|
|
1557
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1558
|
+
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1559
|
+
}
|
|
1560
|
+
yield this.loadSpec();
|
|
1561
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1562
|
+
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1563
|
+
}
|
|
1564
|
+
const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
|
|
1565
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1566
|
+
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1567
|
+
}
|
|
1568
|
+
const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
|
|
1569
|
+
return [newUnResolvedSpec, newSpec];
|
|
1570
|
+
}
|
|
1571
|
+
catch (err) {
|
|
1572
|
+
if (err instanceof SpecParserError) {
|
|
1573
|
+
throw err;
|
|
1574
|
+
}
|
|
1575
|
+
throw new SpecParserError(err.toString(), exports.ErrorType.GetSpecFailed);
|
|
1576
|
+
}
|
|
1577
|
+
});
|
|
1578
|
+
}
|
|
1255
1579
|
/**
|
|
1256
1580
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
1257
1581
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
1258
1582
|
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1259
1583
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
1260
|
-
* @param
|
|
1584
|
+
* @param pluginFilePath File path of the api plugin file to generate.
|
|
1261
1585
|
*/
|
|
1262
|
-
|
|
1586
|
+
generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
1263
1587
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1264
1588
|
const result = {
|
|
1265
1589
|
allSuccess: true,
|
|
1266
1590
|
warnings: [],
|
|
1267
1591
|
};
|
|
1268
1592
|
try {
|
|
1269
|
-
|
|
1270
|
-
|
|
1593
|
+
const newSpecs = yield this.getFilteredSpecs(filter, signal);
|
|
1594
|
+
const newUnResolvedSpec = newSpecs[0];
|
|
1595
|
+
const newSpec = newSpecs[1];
|
|
1596
|
+
let resultStr;
|
|
1597
|
+
if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
|
|
1598
|
+
resultStr = jsyaml__default['default'].dump(newUnResolvedSpec);
|
|
1271
1599
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1600
|
+
else {
|
|
1601
|
+
resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
|
|
1275
1602
|
}
|
|
1276
|
-
|
|
1603
|
+
yield fs__default['default'].outputFile(outputSpecPath, resultStr);
|
|
1277
1604
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1278
1605
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1279
1606
|
}
|
|
1280
|
-
const
|
|
1281
|
-
|
|
1282
|
-
|
|
1607
|
+
const [updatedManifest, apiPlugin] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
|
|
1608
|
+
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1609
|
+
yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
|
|
1610
|
+
}
|
|
1611
|
+
catch (err) {
|
|
1612
|
+
if (err instanceof SpecParserError) {
|
|
1613
|
+
throw err;
|
|
1614
|
+
}
|
|
1615
|
+
throw new SpecParserError(err.toString(), exports.ErrorType.GenerateFailed);
|
|
1616
|
+
}
|
|
1617
|
+
return result;
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
/**
|
|
1621
|
+
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
1622
|
+
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
1623
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1624
|
+
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
1625
|
+
* @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
|
|
1626
|
+
*/
|
|
1627
|
+
generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
1628
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1629
|
+
const result = {
|
|
1630
|
+
allSuccess: true,
|
|
1631
|
+
warnings: [],
|
|
1632
|
+
};
|
|
1633
|
+
try {
|
|
1634
|
+
const newSpecs = yield this.getFilteredSpecs(filter, signal);
|
|
1635
|
+
const newUnResolvedSpec = newSpecs[0];
|
|
1636
|
+
const newSpec = newSpecs[1];
|
|
1637
|
+
let hasMultipleAuth = false;
|
|
1638
|
+
let authInfo = undefined;
|
|
1283
1639
|
for (const url in newSpec.paths) {
|
|
1284
1640
|
for (const method in newSpec.paths[url]) {
|
|
1285
1641
|
const operation = newSpec.paths[url][method];
|
|
1286
1642
|
const authArray = Utils.getAuthArray(operation.security, newSpec);
|
|
1287
1643
|
if (authArray && authArray.length > 0) {
|
|
1288
|
-
|
|
1289
|
-
if (
|
|
1290
|
-
|
|
1644
|
+
const currentAuth = authArray[0][0];
|
|
1645
|
+
if (!authInfo) {
|
|
1646
|
+
authInfo = authArray[0][0];
|
|
1647
|
+
}
|
|
1648
|
+
else if (authInfo.name !== currentAuth.name) {
|
|
1649
|
+
hasMultipleAuth = true;
|
|
1291
1650
|
break;
|
|
1292
1651
|
}
|
|
1293
1652
|
}
|
|
1294
1653
|
}
|
|
1295
1654
|
}
|
|
1296
|
-
if (
|
|
1297
|
-
throw new SpecParserError(ConstantString.
|
|
1655
|
+
if (hasMultipleAuth && this.options.projectType !== exports.ProjectType.TeamsAi) {
|
|
1656
|
+
throw new SpecParserError(ConstantString.MultipleAuthNotSupported, exports.ErrorType.MultipleAuthNotSupported);
|
|
1298
1657
|
}
|
|
1299
1658
|
let resultStr;
|
|
1300
1659
|
if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
|
|
@@ -1304,26 +1663,28 @@ class SpecParser {
|
|
|
1304
1663
|
resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
|
|
1305
1664
|
}
|
|
1306
1665
|
yield fs__default['default'].outputFile(outputSpecPath, resultStr);
|
|
1307
|
-
|
|
1308
|
-
for (const
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1666
|
+
if (adaptiveCardFolder) {
|
|
1667
|
+
for (const url in newSpec.paths) {
|
|
1668
|
+
for (const method in newSpec.paths[url]) {
|
|
1669
|
+
// paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
|
|
1670
|
+
if (this.options.allowMethods.includes(method)) {
|
|
1671
|
+
const operation = newSpec.paths[url][method];
|
|
1672
|
+
try {
|
|
1673
|
+
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
1674
|
+
const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
|
|
1675
|
+
const wrappedCard = wrapAdaptiveCard(card, jsonPath);
|
|
1676
|
+
yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
|
|
1677
|
+
const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
|
|
1678
|
+
yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
|
|
1679
|
+
}
|
|
1680
|
+
catch (err) {
|
|
1681
|
+
result.allSuccess = false;
|
|
1682
|
+
result.warnings.push({
|
|
1683
|
+
type: exports.WarningType.GenerateCardFailed,
|
|
1684
|
+
content: err.toString(),
|
|
1685
|
+
data: operation.operationId,
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1327
1688
|
}
|
|
1328
1689
|
}
|
|
1329
1690
|
}
|
|
@@ -1331,8 +1692,7 @@ class SpecParser {
|
|
|
1331
1692
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1332
1693
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1333
1694
|
}
|
|
1334
|
-
const
|
|
1335
|
-
const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth);
|
|
1695
|
+
const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
|
|
1336
1696
|
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1337
1697
|
result.warnings.push(...warnings);
|
|
1338
1698
|
}
|
|
@@ -1360,16 +1720,17 @@ class SpecParser {
|
|
|
1360
1720
|
}
|
|
1361
1721
|
});
|
|
1362
1722
|
}
|
|
1363
|
-
|
|
1723
|
+
getAPIs(spec) {
|
|
1364
1724
|
if (this.apiMap !== undefined) {
|
|
1365
1725
|
return this.apiMap;
|
|
1366
1726
|
}
|
|
1367
|
-
const result = Utils.
|
|
1727
|
+
const result = Utils.listAPIs(spec, this.options);
|
|
1368
1728
|
this.apiMap = result;
|
|
1369
1729
|
return result;
|
|
1370
1730
|
}
|
|
1371
1731
|
}
|
|
1372
1732
|
|
|
1733
|
+
exports.AdaptiveCardGenerator = AdaptiveCardGenerator;
|
|
1373
1734
|
exports.ConstantString = ConstantString;
|
|
1374
1735
|
exports.SpecParser = SpecParser;
|
|
1375
1736
|
exports.SpecParserError = SpecParserError;
|