@microsoft/m365-spec-parser 0.1.1-alpha.78701ec6a.0 → 0.1.1-alpha.87f45d762.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 +803 -299
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +983 -409
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +807 -299
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +991 -408
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +6 -1
- package/dist/src/index.browser.d.ts +2 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/interfaces.d.ts +90 -18
- package/dist/src/manifestUpdater.d.ts +9 -4
- package/dist/src/specFilter.d.ts +2 -1
- package/dist/src/specParser.browser.d.ts +18 -2
- package/dist/src/specParser.d.ts +18 -3
- package/dist/src/utils.d.ts +18 -34
- 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,9 @@ 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;
|
|
212
|
+
ConstantString.DefaultPluginId = "plugin_1";
|
|
185
213
|
|
|
186
214
|
// Copyright (c) Microsoft Corporation.
|
|
187
215
|
class SpecParserError extends Error {
|
|
@@ -193,201 +221,30 @@ class SpecParserError extends Error {
|
|
|
193
221
|
|
|
194
222
|
// Copyright (c) Microsoft Corporation.
|
|
195
223
|
class Utils {
|
|
196
|
-
static
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
};
|
|
202
|
-
if (!paramObject) {
|
|
203
|
-
return paramResult;
|
|
204
|
-
}
|
|
205
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
206
|
-
const param = paramObject[i];
|
|
207
|
-
const schema = param.schema;
|
|
208
|
-
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
209
|
-
if (param.in === "header" || param.in === "cookie") {
|
|
210
|
-
if (isRequiredWithoutDefault) {
|
|
211
|
-
paramResult.isValid = false;
|
|
212
|
-
}
|
|
213
|
-
continue;
|
|
214
|
-
}
|
|
215
|
-
if (schema.type !== "boolean" &&
|
|
216
|
-
schema.type !== "string" &&
|
|
217
|
-
schema.type !== "number" &&
|
|
218
|
-
schema.type !== "integer") {
|
|
219
|
-
if (isRequiredWithoutDefault) {
|
|
220
|
-
paramResult.isValid = false;
|
|
221
|
-
}
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
if (param.in === "query" || param.in === "path") {
|
|
225
|
-
if (isRequiredWithoutDefault) {
|
|
226
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return paramResult;
|
|
234
|
-
}
|
|
235
|
-
static checkPostBody(schema, isRequired = false) {
|
|
236
|
-
var _a;
|
|
237
|
-
const paramResult = {
|
|
238
|
-
requiredNum: 0,
|
|
239
|
-
optionalNum: 0,
|
|
240
|
-
isValid: true,
|
|
241
|
-
};
|
|
242
|
-
if (Object.keys(schema).length === 0) {
|
|
243
|
-
return paramResult;
|
|
244
|
-
}
|
|
245
|
-
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
246
|
-
if (schema.type === "string" ||
|
|
247
|
-
schema.type === "integer" ||
|
|
248
|
-
schema.type === "boolean" ||
|
|
249
|
-
schema.type === "number") {
|
|
250
|
-
if (isRequiredWithoutDefault) {
|
|
251
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
else if (schema.type === "object") {
|
|
258
|
-
const { properties } = schema;
|
|
259
|
-
for (const property in properties) {
|
|
260
|
-
let isRequired = false;
|
|
261
|
-
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
262
|
-
isRequired = true;
|
|
263
|
-
}
|
|
264
|
-
const result = Utils.checkPostBody(properties[property], isRequired);
|
|
265
|
-
paramResult.requiredNum += result.requiredNum;
|
|
266
|
-
paramResult.optionalNum += result.optionalNum;
|
|
267
|
-
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
if (isRequiredWithoutDefault) {
|
|
272
|
-
paramResult.isValid = false;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return paramResult;
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Checks if the given API is supported.
|
|
279
|
-
* @param {string} method - The HTTP method of the API.
|
|
280
|
-
* @param {string} path - The path of the API.
|
|
281
|
-
* @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
|
|
282
|
-
* @returns {boolean} - Returns true if the API is supported, false otherwise.
|
|
283
|
-
* @description The following APIs are supported:
|
|
284
|
-
* 1. only support Get/Post operation without auth property
|
|
285
|
-
* 2. parameter inside query or path only support string, number, boolean and integer
|
|
286
|
-
* 3. parameter inside post body only support string, number, boolean, integer and object
|
|
287
|
-
* 4. request body + required parameters <= 1
|
|
288
|
-
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
289
|
-
* 6. only support request body with “application/json” content type
|
|
290
|
-
*/
|
|
291
|
-
static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
|
|
292
|
-
const pathObj = spec.paths[path];
|
|
293
|
-
method = method.toLocaleLowerCase();
|
|
294
|
-
if (pathObj) {
|
|
295
|
-
if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
|
|
296
|
-
pathObj[method]) {
|
|
297
|
-
const securities = pathObj[method].security;
|
|
298
|
-
const authArray = Utils.getAuthArray(securities, spec);
|
|
299
|
-
if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
|
|
300
|
-
return false;
|
|
301
|
-
}
|
|
302
|
-
const operationObject = pathObj[method];
|
|
303
|
-
if (!allowMissingId && !operationObject.operationId) {
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
const paramObject = operationObject.parameters;
|
|
307
|
-
const requestBody = operationObject.requestBody;
|
|
308
|
-
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
309
|
-
const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
|
|
310
|
-
if (mediaTypesCount > 1) {
|
|
311
|
-
return false;
|
|
312
|
-
}
|
|
313
|
-
const responseJson = Utils.getResponseJson(operationObject);
|
|
314
|
-
if (Object.keys(responseJson).length === 0) {
|
|
315
|
-
return false;
|
|
316
|
-
}
|
|
317
|
-
let requestBodyParamResult = {
|
|
318
|
-
requiredNum: 0,
|
|
319
|
-
optionalNum: 0,
|
|
320
|
-
isValid: true,
|
|
321
|
-
};
|
|
322
|
-
if (requestJsonBody) {
|
|
323
|
-
const requestBodySchema = requestJsonBody.schema;
|
|
324
|
-
requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
|
|
325
|
-
}
|
|
326
|
-
if (!requestBodyParamResult.isValid) {
|
|
327
|
-
return false;
|
|
328
|
-
}
|
|
329
|
-
const paramResult = Utils.checkParameters(paramObject);
|
|
330
|
-
if (!paramResult.isValid) {
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
|
-
if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
|
|
334
|
-
if (allowMultipleParameters &&
|
|
335
|
-
requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
|
|
336
|
-
return true;
|
|
337
|
-
}
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
else if (requestBodyParamResult.requiredNum +
|
|
341
|
-
requestBodyParamResult.optionalNum +
|
|
342
|
-
paramResult.requiredNum +
|
|
343
|
-
paramResult.optionalNum ===
|
|
344
|
-
0) {
|
|
345
|
-
return false;
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
224
|
+
static hasNestedObjectInSchema(schema) {
|
|
225
|
+
if (schema.type === "object") {
|
|
226
|
+
for (const property in schema.properties) {
|
|
227
|
+
const nestedSchema = schema.properties[property];
|
|
228
|
+
if (nestedSchema.type === "object") {
|
|
348
229
|
return true;
|
|
349
230
|
}
|
|
350
231
|
}
|
|
351
232
|
}
|
|
352
233
|
return false;
|
|
353
234
|
}
|
|
354
|
-
static
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
// Currently we don't support multiple auth in one operation
|
|
360
|
-
if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
|
|
361
|
-
return false;
|
|
362
|
-
}
|
|
363
|
-
for (const auths of authSchemaArray) {
|
|
364
|
-
if (auths.length === 1) {
|
|
365
|
-
if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
|
|
366
|
-
return true;
|
|
367
|
-
}
|
|
368
|
-
else if (!allowAPIKeyAuth &&
|
|
369
|
-
allowOauth2 &&
|
|
370
|
-
Utils.isBearerTokenAuth(auths[0].authSchema)) {
|
|
371
|
-
return true;
|
|
372
|
-
}
|
|
373
|
-
else if (allowAPIKeyAuth &&
|
|
374
|
-
allowOauth2 &&
|
|
375
|
-
(Utils.isAPIKeyAuth(auths[0].authSchema) ||
|
|
376
|
-
Utils.isBearerTokenAuth(auths[0].authSchema))) {
|
|
377
|
-
return true;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
return false;
|
|
235
|
+
static containMultipleMediaTypes(bodyObject) {
|
|
236
|
+
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
237
|
+
}
|
|
238
|
+
static isBearerTokenAuth(authScheme) {
|
|
239
|
+
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
383
240
|
}
|
|
384
|
-
static isAPIKeyAuth(
|
|
385
|
-
return
|
|
241
|
+
static isAPIKeyAuth(authScheme) {
|
|
242
|
+
return authScheme.type === "apiKey";
|
|
386
243
|
}
|
|
387
|
-
static
|
|
388
|
-
return (
|
|
389
|
-
|
|
390
|
-
|
|
244
|
+
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
245
|
+
return !!(authScheme.type === "oauth2" &&
|
|
246
|
+
authScheme.flows &&
|
|
247
|
+
authScheme.flows.authorizationCode);
|
|
391
248
|
}
|
|
392
249
|
static getAuthArray(securities, spec) {
|
|
393
250
|
var _a;
|
|
@@ -400,7 +257,7 @@ class Utils {
|
|
|
400
257
|
for (const name in security) {
|
|
401
258
|
const auth = securitySchemas[name];
|
|
402
259
|
authArray.push({
|
|
403
|
-
|
|
260
|
+
authScheme: auth,
|
|
404
261
|
name: name,
|
|
405
262
|
});
|
|
406
263
|
}
|
|
@@ -418,18 +275,22 @@ class Utils {
|
|
|
418
275
|
static getResponseJson(operationObject) {
|
|
419
276
|
var _a, _b;
|
|
420
277
|
let json = {};
|
|
278
|
+
let multipleMediaType = false;
|
|
421
279
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
422
280
|
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
281
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
282
|
+
multipleMediaType = false;
|
|
428
283
|
json = responseObject.content["application/json"];
|
|
429
|
-
|
|
284
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
285
|
+
multipleMediaType = true;
|
|
286
|
+
json = {};
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
430
291
|
}
|
|
431
292
|
}
|
|
432
|
-
return json;
|
|
293
|
+
return { json, multipleMediaType };
|
|
433
294
|
}
|
|
434
295
|
static convertPathToCamelCase(path) {
|
|
435
296
|
const pathSegments = path.split(/[./{]/);
|
|
@@ -449,10 +310,10 @@ class Utils {
|
|
|
449
310
|
return undefined;
|
|
450
311
|
}
|
|
451
312
|
}
|
|
452
|
-
static
|
|
313
|
+
static resolveEnv(str) {
|
|
453
314
|
const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
|
|
454
|
-
let matches = placeHolderReg.exec(
|
|
455
|
-
let
|
|
315
|
+
let matches = placeHolderReg.exec(str);
|
|
316
|
+
let newStr = str;
|
|
456
317
|
while (matches != null) {
|
|
457
318
|
const envVar = matches[1];
|
|
458
319
|
const envVal = process.env[envVar];
|
|
@@ -460,17 +321,17 @@ class Utils {
|
|
|
460
321
|
throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
|
|
461
322
|
}
|
|
462
323
|
else {
|
|
463
|
-
|
|
324
|
+
newStr = newStr.replace(matches[0], envVal);
|
|
464
325
|
}
|
|
465
|
-
matches = placeHolderReg.exec(
|
|
326
|
+
matches = placeHolderReg.exec(str);
|
|
466
327
|
}
|
|
467
|
-
return
|
|
328
|
+
return newStr;
|
|
468
329
|
}
|
|
469
330
|
static checkServerUrl(servers) {
|
|
470
331
|
const errors = [];
|
|
471
332
|
let serverUrl;
|
|
472
333
|
try {
|
|
473
|
-
serverUrl = Utils.
|
|
334
|
+
serverUrl = Utils.resolveEnv(servers[0].url);
|
|
474
335
|
}
|
|
475
336
|
catch (err) {
|
|
476
337
|
errors.push({
|
|
@@ -500,7 +361,8 @@ class Utils {
|
|
|
500
361
|
}
|
|
501
362
|
return errors;
|
|
502
363
|
}
|
|
503
|
-
static validateServer(spec,
|
|
364
|
+
static validateServer(spec, options) {
|
|
365
|
+
var _a;
|
|
504
366
|
const errors = [];
|
|
505
367
|
let hasTopLevelServers = false;
|
|
506
368
|
let hasPathLevelServers = false;
|
|
@@ -521,7 +383,7 @@ class Utils {
|
|
|
521
383
|
}
|
|
522
384
|
for (const method in methods) {
|
|
523
385
|
const operationObject = methods[method];
|
|
524
|
-
if (
|
|
386
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
525
387
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
526
388
|
hasOperationLevelServers = true;
|
|
527
389
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -564,6 +426,7 @@ class Utils {
|
|
|
564
426
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
565
427
|
}
|
|
566
428
|
if (isRequired && schema.default === undefined) {
|
|
429
|
+
parameter.isRequired = true;
|
|
567
430
|
requiredParams.push(parameter);
|
|
568
431
|
}
|
|
569
432
|
else {
|
|
@@ -608,7 +471,7 @@ class Utils {
|
|
|
608
471
|
param.value = schema.default;
|
|
609
472
|
}
|
|
610
473
|
}
|
|
611
|
-
static parseApiInfo(operationItem,
|
|
474
|
+
static parseApiInfo(operationItem, options) {
|
|
612
475
|
var _a, _b;
|
|
613
476
|
const requiredParams = [];
|
|
614
477
|
const optionalParams = [];
|
|
@@ -622,11 +485,12 @@ class Utils {
|
|
|
622
485
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
623
486
|
};
|
|
624
487
|
const schema = param.schema;
|
|
625
|
-
if (allowMultipleParameters && schema) {
|
|
488
|
+
if (options.allowMultipleParameters && schema) {
|
|
626
489
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
627
490
|
}
|
|
628
491
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
629
492
|
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
493
|
+
parameter.isRequired = true;
|
|
630
494
|
requiredParams.push(parameter);
|
|
631
495
|
}
|
|
632
496
|
else {
|
|
@@ -640,19 +504,13 @@ class Utils {
|
|
|
640
504
|
const requestJson = requestBody.content["application/json"];
|
|
641
505
|
if (Object.keys(requestJson).length !== 0) {
|
|
642
506
|
const schema = requestJson.schema;
|
|
643
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
507
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
644
508
|
requiredParams.push(...requiredP);
|
|
645
509
|
optionalParams.push(...optionalP);
|
|
646
510
|
}
|
|
647
511
|
}
|
|
648
512
|
const operationId = operationItem.operationId;
|
|
649
|
-
const parameters = [];
|
|
650
|
-
if (requiredParams.length !== 0) {
|
|
651
|
-
parameters.push(...requiredParams);
|
|
652
|
-
}
|
|
653
|
-
else {
|
|
654
|
-
parameters.push(optionalParams[0]);
|
|
655
|
-
}
|
|
513
|
+
const parameters = [...requiredParams, ...optionalParams];
|
|
656
514
|
const command = {
|
|
657
515
|
context: ["compose"],
|
|
658
516
|
type: "query",
|
|
@@ -661,130 +519,568 @@ class Utils {
|
|
|
661
519
|
parameters: parameters,
|
|
662
520
|
description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
|
|
663
521
|
};
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
522
|
+
return command;
|
|
523
|
+
}
|
|
524
|
+
static format(str, ...args) {
|
|
525
|
+
let index = 0;
|
|
526
|
+
return str.replace(/%s/g, () => {
|
|
527
|
+
const arg = args[index++];
|
|
528
|
+
return arg !== undefined ? arg : "";
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
static getSafeRegistrationIdEnvName(authName) {
|
|
532
|
+
if (!authName) {
|
|
533
|
+
return "";
|
|
534
|
+
}
|
|
535
|
+
let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
|
|
536
|
+
if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
|
|
537
|
+
safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
|
|
671
538
|
}
|
|
672
|
-
return
|
|
539
|
+
return safeRegistrationIdEnvName;
|
|
673
540
|
}
|
|
674
|
-
static
|
|
675
|
-
const
|
|
541
|
+
static getServerObject(spec, method, path) {
|
|
542
|
+
const pathObj = spec.paths[path];
|
|
543
|
+
const operationObject = pathObj[method];
|
|
544
|
+
const rootServer = spec.servers && spec.servers[0];
|
|
545
|
+
const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
|
|
546
|
+
const operationServer = operationObject.servers && operationObject.servers[0];
|
|
547
|
+
const serverUrl = operationServer || methodServer || rootServer;
|
|
548
|
+
return serverUrl;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Copyright (c) Microsoft Corporation.
|
|
553
|
+
class Validator {
|
|
554
|
+
listAPIs() {
|
|
555
|
+
var _a;
|
|
556
|
+
if (this.apiMap) {
|
|
557
|
+
return this.apiMap;
|
|
558
|
+
}
|
|
559
|
+
const paths = this.spec.paths;
|
|
676
560
|
const result = {};
|
|
677
561
|
for (const path in paths) {
|
|
678
562
|
const methods = paths[path];
|
|
679
563
|
for (const method in methods) {
|
|
680
|
-
|
|
681
|
-
if (
|
|
682
|
-
const
|
|
683
|
-
result[`${method.toUpperCase()} ${path}`] =
|
|
564
|
+
const operationObject = methods[method];
|
|
565
|
+
if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
566
|
+
const validateResult = this.validateAPI(method, path);
|
|
567
|
+
result[`${method.toUpperCase()} ${path}`] = {
|
|
568
|
+
operation: operationObject,
|
|
569
|
+
isValid: validateResult.isValid,
|
|
570
|
+
reason: validateResult.reason,
|
|
571
|
+
};
|
|
684
572
|
}
|
|
685
573
|
}
|
|
686
574
|
}
|
|
575
|
+
this.apiMap = result;
|
|
687
576
|
return result;
|
|
688
577
|
}
|
|
689
|
-
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
578
|
+
validateSpecVersion() {
|
|
579
|
+
const result = { errors: [], warnings: [] };
|
|
580
|
+
if (this.spec.openapi >= "3.1.0") {
|
|
581
|
+
result.errors.push({
|
|
582
|
+
type: exports.ErrorType.SpecVersionNotSupported,
|
|
583
|
+
content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
|
|
584
|
+
data: this.spec.openapi,
|
|
696
585
|
});
|
|
697
586
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
587
|
+
return result;
|
|
588
|
+
}
|
|
589
|
+
validateSpecServer() {
|
|
590
|
+
const result = { errors: [], warnings: [] };
|
|
591
|
+
const serverErrors = Utils.validateServer(this.spec, this.options);
|
|
592
|
+
result.errors.push(...serverErrors);
|
|
593
|
+
return result;
|
|
594
|
+
}
|
|
595
|
+
validateSpecNoSupportAPI() {
|
|
596
|
+
const result = { errors: [], warnings: [] };
|
|
597
|
+
const apiMap = this.listAPIs();
|
|
598
|
+
const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
|
|
599
|
+
if (validAPIs.length === 0) {
|
|
600
|
+
const data = [];
|
|
601
|
+
for (const key in apiMap) {
|
|
602
|
+
const { reason } = apiMap[key];
|
|
603
|
+
const apiInvalidReason = { api: key, reason: reason };
|
|
604
|
+
data.push(apiInvalidReason);
|
|
605
|
+
}
|
|
606
|
+
result.errors.push({
|
|
715
607
|
type: exports.ErrorType.NoSupportedApi,
|
|
716
608
|
content: ConstantString.NoSupportedApi,
|
|
609
|
+
data,
|
|
717
610
|
});
|
|
718
611
|
}
|
|
612
|
+
return result;
|
|
613
|
+
}
|
|
614
|
+
validateSpecOperationId() {
|
|
615
|
+
const result = { errors: [], warnings: [] };
|
|
616
|
+
const apiMap = this.listAPIs();
|
|
719
617
|
// OperationId missing
|
|
720
618
|
const apisMissingOperationId = [];
|
|
721
619
|
for (const key in apiMap) {
|
|
722
|
-
const
|
|
723
|
-
if (!
|
|
620
|
+
const { operation } = apiMap[key];
|
|
621
|
+
if (!operation.operationId) {
|
|
724
622
|
apisMissingOperationId.push(key);
|
|
725
623
|
}
|
|
726
624
|
}
|
|
727
625
|
if (apisMissingOperationId.length > 0) {
|
|
728
|
-
warnings.push({
|
|
626
|
+
result.warnings.push({
|
|
729
627
|
type: exports.WarningType.OperationIdMissing,
|
|
730
628
|
content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
|
|
731
629
|
data: apisMissingOperationId,
|
|
732
630
|
});
|
|
733
631
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
632
|
+
return result;
|
|
633
|
+
}
|
|
634
|
+
validateMethodAndPath(method, path) {
|
|
635
|
+
const result = { isValid: true, reason: [] };
|
|
636
|
+
if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
|
|
637
|
+
result.isValid = false;
|
|
638
|
+
result.reason.push(exports.ErrorType.MethodNotAllowed);
|
|
639
|
+
return result;
|
|
640
|
+
}
|
|
641
|
+
const pathObj = this.spec.paths[path];
|
|
642
|
+
if (!pathObj || !pathObj[method]) {
|
|
643
|
+
result.isValid = false;
|
|
644
|
+
result.reason.push(exports.ErrorType.UrlPathNotExist);
|
|
645
|
+
return result;
|
|
646
|
+
}
|
|
647
|
+
return result;
|
|
648
|
+
}
|
|
649
|
+
validateResponse(method, path) {
|
|
650
|
+
const result = { isValid: true, reason: [] };
|
|
651
|
+
const operationObject = this.spec.paths[path][method];
|
|
652
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
653
|
+
// only support response body only contains “application/json” content type
|
|
654
|
+
if (multipleMediaType) {
|
|
655
|
+
result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
|
|
656
|
+
}
|
|
657
|
+
else if (Object.keys(json).length === 0) {
|
|
658
|
+
// response body should not be empty
|
|
659
|
+
result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
|
|
660
|
+
}
|
|
661
|
+
return result;
|
|
662
|
+
}
|
|
663
|
+
validateServer(method, path) {
|
|
664
|
+
const result = { isValid: true, reason: [] };
|
|
665
|
+
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
666
|
+
if (!serverObj) {
|
|
667
|
+
// should contain server URL
|
|
668
|
+
result.reason.push(exports.ErrorType.NoServerInformation);
|
|
669
|
+
}
|
|
670
|
+
else {
|
|
671
|
+
// server url should be absolute url with https protocol
|
|
672
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
673
|
+
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
737
674
|
}
|
|
738
|
-
|
|
739
|
-
|
|
675
|
+
return result;
|
|
676
|
+
}
|
|
677
|
+
validateAuth(method, path) {
|
|
678
|
+
const pathObj = this.spec.paths[path];
|
|
679
|
+
const operationObject = pathObj[method];
|
|
680
|
+
const securities = operationObject.security;
|
|
681
|
+
const authSchemeArray = Utils.getAuthArray(securities, this.spec);
|
|
682
|
+
if (authSchemeArray.length === 0) {
|
|
683
|
+
return { isValid: true, reason: [] };
|
|
740
684
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
685
|
+
if (this.options.allowAPIKeyAuth ||
|
|
686
|
+
this.options.allowOauth2 ||
|
|
687
|
+
this.options.allowBearerTokenAuth) {
|
|
688
|
+
// Currently we don't support multiple auth in one operation
|
|
689
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
690
|
+
return {
|
|
691
|
+
isValid: false,
|
|
692
|
+
reason: [exports.ErrorType.MultipleAuthNotSupported],
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
for (const auths of authSchemeArray) {
|
|
696
|
+
if (auths.length === 1) {
|
|
697
|
+
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
698
|
+
(this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
|
|
699
|
+
(this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
|
|
700
|
+
return { isValid: true, reason: [] };
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
|
|
706
|
+
}
|
|
707
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
708
|
+
var _a;
|
|
709
|
+
const paramResult = {
|
|
710
|
+
requiredNum: 0,
|
|
711
|
+
optionalNum: 0,
|
|
712
|
+
isValid: true,
|
|
713
|
+
reason: [],
|
|
745
714
|
};
|
|
715
|
+
if (Object.keys(schema).length === 0) {
|
|
716
|
+
return paramResult;
|
|
717
|
+
}
|
|
718
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
719
|
+
const isCopilot = this.projectType === exports.ProjectType.Copilot;
|
|
720
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
721
|
+
paramResult.isValid = false;
|
|
722
|
+
paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
|
|
723
|
+
return paramResult;
|
|
724
|
+
}
|
|
725
|
+
if (schema.type === "string" ||
|
|
726
|
+
schema.type === "integer" ||
|
|
727
|
+
schema.type === "boolean" ||
|
|
728
|
+
schema.type === "number") {
|
|
729
|
+
if (isRequiredWithoutDefault) {
|
|
730
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
else if (schema.type === "object") {
|
|
737
|
+
const { properties } = schema;
|
|
738
|
+
for (const property in properties) {
|
|
739
|
+
let isRequired = false;
|
|
740
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
741
|
+
isRequired = true;
|
|
742
|
+
}
|
|
743
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
744
|
+
paramResult.requiredNum += result.requiredNum;
|
|
745
|
+
paramResult.optionalNum += result.optionalNum;
|
|
746
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
747
|
+
paramResult.reason.push(...result.reason);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
751
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
752
|
+
paramResult.isValid = false;
|
|
753
|
+
paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return paramResult;
|
|
746
757
|
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
758
|
+
checkParamSchema(paramObject) {
|
|
759
|
+
const paramResult = {
|
|
760
|
+
requiredNum: 0,
|
|
761
|
+
optionalNum: 0,
|
|
762
|
+
isValid: true,
|
|
763
|
+
reason: [],
|
|
764
|
+
};
|
|
765
|
+
if (!paramObject) {
|
|
766
|
+
return paramResult;
|
|
767
|
+
}
|
|
768
|
+
const isCopilot = this.projectType === exports.ProjectType.Copilot;
|
|
769
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
770
|
+
const param = paramObject[i];
|
|
771
|
+
const schema = param.schema;
|
|
772
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
773
|
+
paramResult.isValid = false;
|
|
774
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
778
|
+
if (isCopilot) {
|
|
779
|
+
if (isRequiredWithoutDefault) {
|
|
780
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
784
|
+
}
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
788
|
+
if (isRequiredWithoutDefault) {
|
|
789
|
+
paramResult.isValid = false;
|
|
790
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
791
|
+
}
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
if (schema.type !== "boolean" &&
|
|
795
|
+
schema.type !== "string" &&
|
|
796
|
+
schema.type !== "number" &&
|
|
797
|
+
schema.type !== "integer") {
|
|
798
|
+
if (isRequiredWithoutDefault) {
|
|
799
|
+
paramResult.isValid = false;
|
|
800
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
801
|
+
}
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
if (param.in === "query" || param.in === "path") {
|
|
805
|
+
if (isRequiredWithoutDefault) {
|
|
806
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
return paramResult;
|
|
753
814
|
}
|
|
754
|
-
|
|
755
|
-
if (
|
|
756
|
-
|
|
815
|
+
hasNestedObjectInSchema(schema) {
|
|
816
|
+
if (schema.type === "object") {
|
|
817
|
+
for (const property in schema.properties) {
|
|
818
|
+
const nestedSchema = schema.properties[property];
|
|
819
|
+
if (nestedSchema.type === "object") {
|
|
820
|
+
return true;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
757
823
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// Copyright (c) Microsoft Corporation.
|
|
829
|
+
class CopilotValidator extends Validator {
|
|
830
|
+
constructor(spec, options) {
|
|
831
|
+
super();
|
|
832
|
+
this.projectType = exports.ProjectType.Copilot;
|
|
833
|
+
this.options = options;
|
|
834
|
+
this.spec = spec;
|
|
835
|
+
}
|
|
836
|
+
validateSpec() {
|
|
837
|
+
const result = { errors: [], warnings: [] };
|
|
838
|
+
// validate spec version
|
|
839
|
+
let validationResult = this.validateSpecVersion();
|
|
840
|
+
result.errors.push(...validationResult.errors);
|
|
841
|
+
// validate spec server
|
|
842
|
+
validationResult = this.validateSpecServer();
|
|
843
|
+
result.errors.push(...validationResult.errors);
|
|
844
|
+
// validate no supported API
|
|
845
|
+
validationResult = this.validateSpecNoSupportAPI();
|
|
846
|
+
result.errors.push(...validationResult.errors);
|
|
847
|
+
// validate operationId missing
|
|
848
|
+
validationResult = this.validateSpecOperationId();
|
|
849
|
+
result.warnings.push(...validationResult.warnings);
|
|
850
|
+
return result;
|
|
851
|
+
}
|
|
852
|
+
validateAPI(method, path) {
|
|
853
|
+
const result = { isValid: true, reason: [] };
|
|
854
|
+
method = method.toLocaleLowerCase();
|
|
855
|
+
// validate method and path
|
|
856
|
+
const methodAndPathResult = this.validateMethodAndPath(method, path);
|
|
857
|
+
if (!methodAndPathResult.isValid) {
|
|
858
|
+
return methodAndPathResult;
|
|
859
|
+
}
|
|
860
|
+
const operationObject = this.spec.paths[path][method];
|
|
861
|
+
// validate auth
|
|
862
|
+
const authCheckResult = this.validateAuth(method, path);
|
|
863
|
+
result.reason.push(...authCheckResult.reason);
|
|
864
|
+
// validate operationId
|
|
865
|
+
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
866
|
+
result.reason.push(exports.ErrorType.MissingOperationId);
|
|
867
|
+
}
|
|
868
|
+
// validate server
|
|
869
|
+
const validateServerResult = this.validateServer(method, path);
|
|
870
|
+
result.reason.push(...validateServerResult.reason);
|
|
871
|
+
// validate response
|
|
872
|
+
const validateResponseResult = this.validateResponse(method, path);
|
|
873
|
+
result.reason.push(...validateResponseResult.reason);
|
|
874
|
+
// validate requestBody
|
|
875
|
+
const requestBody = operationObject.requestBody;
|
|
876
|
+
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
877
|
+
if (Utils.containMultipleMediaTypes(requestBody)) {
|
|
878
|
+
result.reason.push(exports.ErrorType.PostBodyContainMultipleMediaTypes);
|
|
879
|
+
}
|
|
880
|
+
if (requestJsonBody) {
|
|
881
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
882
|
+
if (requestBodySchema.type !== "object") {
|
|
883
|
+
result.reason.push(exports.ErrorType.PostBodySchemaIsNotJson);
|
|
884
|
+
}
|
|
885
|
+
const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
886
|
+
result.reason.push(...requestBodyParamResult.reason);
|
|
887
|
+
}
|
|
888
|
+
// validate parameters
|
|
889
|
+
const paramObject = operationObject.parameters;
|
|
890
|
+
const paramResult = this.checkParamSchema(paramObject);
|
|
891
|
+
result.reason.push(...paramResult.reason);
|
|
892
|
+
if (result.reason.length > 0) {
|
|
893
|
+
result.isValid = false;
|
|
894
|
+
}
|
|
895
|
+
return result;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// Copyright (c) Microsoft Corporation.
|
|
900
|
+
class SMEValidator extends Validator {
|
|
901
|
+
constructor(spec, options) {
|
|
902
|
+
super();
|
|
903
|
+
this.projectType = exports.ProjectType.SME;
|
|
904
|
+
this.options = options;
|
|
905
|
+
this.spec = spec;
|
|
906
|
+
}
|
|
907
|
+
validateSpec() {
|
|
908
|
+
const result = { errors: [], warnings: [] };
|
|
909
|
+
// validate spec version
|
|
910
|
+
let validationResult = this.validateSpecVersion();
|
|
911
|
+
result.errors.push(...validationResult.errors);
|
|
912
|
+
// validate spec server
|
|
913
|
+
validationResult = this.validateSpecServer();
|
|
914
|
+
result.errors.push(...validationResult.errors);
|
|
915
|
+
// validate no supported API
|
|
916
|
+
validationResult = this.validateSpecNoSupportAPI();
|
|
917
|
+
result.errors.push(...validationResult.errors);
|
|
918
|
+
// validate operationId missing
|
|
919
|
+
if (this.options.allowMissingId) {
|
|
920
|
+
validationResult = this.validateSpecOperationId();
|
|
921
|
+
result.warnings.push(...validationResult.warnings);
|
|
922
|
+
}
|
|
923
|
+
return result;
|
|
924
|
+
}
|
|
925
|
+
validateAPI(method, path) {
|
|
926
|
+
const result = { isValid: true, reason: [] };
|
|
927
|
+
method = method.toLocaleLowerCase();
|
|
928
|
+
// validate method and path
|
|
929
|
+
const methodAndPathResult = this.validateMethodAndPath(method, path);
|
|
930
|
+
if (!methodAndPathResult.isValid) {
|
|
931
|
+
return methodAndPathResult;
|
|
932
|
+
}
|
|
933
|
+
const operationObject = this.spec.paths[path][method];
|
|
934
|
+
// validate auth
|
|
935
|
+
const authCheckResult = this.validateAuth(method, path);
|
|
936
|
+
result.reason.push(...authCheckResult.reason);
|
|
937
|
+
// validate operationId
|
|
938
|
+
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
939
|
+
result.reason.push(exports.ErrorType.MissingOperationId);
|
|
940
|
+
}
|
|
941
|
+
// validate server
|
|
942
|
+
const validateServerResult = this.validateServer(method, path);
|
|
943
|
+
result.reason.push(...validateServerResult.reason);
|
|
944
|
+
// validate response
|
|
945
|
+
const validateResponseResult = this.validateResponse(method, path);
|
|
946
|
+
result.reason.push(...validateResponseResult.reason);
|
|
947
|
+
let postBodyResult = {
|
|
948
|
+
requiredNum: 0,
|
|
949
|
+
optionalNum: 0,
|
|
950
|
+
isValid: true,
|
|
951
|
+
reason: [],
|
|
952
|
+
};
|
|
953
|
+
// validate requestBody
|
|
954
|
+
const requestBody = operationObject.requestBody;
|
|
955
|
+
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
956
|
+
if (Utils.containMultipleMediaTypes(requestBody)) {
|
|
957
|
+
result.reason.push(exports.ErrorType.PostBodyContainMultipleMediaTypes);
|
|
958
|
+
}
|
|
959
|
+
if (requestJsonBody) {
|
|
960
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
961
|
+
postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
962
|
+
result.reason.push(...postBodyResult.reason);
|
|
963
|
+
}
|
|
964
|
+
// validate parameters
|
|
965
|
+
const paramObject = operationObject.parameters;
|
|
966
|
+
const paramResult = this.checkParamSchema(paramObject);
|
|
967
|
+
result.reason.push(...paramResult.reason);
|
|
968
|
+
// validate total parameters count
|
|
969
|
+
if (paramResult.isValid && postBodyResult.isValid) {
|
|
970
|
+
const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
|
|
971
|
+
result.reason.push(...paramCountResult.reason);
|
|
972
|
+
}
|
|
973
|
+
if (result.reason.length > 0) {
|
|
974
|
+
result.isValid = false;
|
|
975
|
+
}
|
|
976
|
+
return result;
|
|
977
|
+
}
|
|
978
|
+
validateParamCount(postBodyResult, paramResult) {
|
|
979
|
+
const result = { isValid: true, reason: [] };
|
|
980
|
+
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
981
|
+
const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
|
|
982
|
+
if (totalRequiredParams > 1) {
|
|
983
|
+
if (!this.options.allowMultipleParameters ||
|
|
984
|
+
totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
|
|
985
|
+
result.reason.push(exports.ErrorType.ExceededRequiredParamsLimit);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
else if (totalParams === 0) {
|
|
989
|
+
result.reason.push(exports.ErrorType.NoParameter);
|
|
990
|
+
}
|
|
991
|
+
return result;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
SMEValidator.SMERequiredParamsMaxNum = 5;
|
|
995
|
+
|
|
996
|
+
// Copyright (c) Microsoft Corporation.
|
|
997
|
+
class TeamsAIValidator extends Validator {
|
|
998
|
+
constructor(spec, options) {
|
|
999
|
+
super();
|
|
1000
|
+
this.projectType = exports.ProjectType.TeamsAi;
|
|
1001
|
+
this.options = options;
|
|
1002
|
+
this.spec = spec;
|
|
1003
|
+
}
|
|
1004
|
+
validateSpec() {
|
|
1005
|
+
const result = { errors: [], warnings: [] };
|
|
1006
|
+
// validate spec server
|
|
1007
|
+
let validationResult = this.validateSpecServer();
|
|
1008
|
+
result.errors.push(...validationResult.errors);
|
|
1009
|
+
// validate no supported API
|
|
1010
|
+
validationResult = this.validateSpecNoSupportAPI();
|
|
1011
|
+
result.errors.push(...validationResult.errors);
|
|
1012
|
+
return result;
|
|
1013
|
+
}
|
|
1014
|
+
validateAPI(method, path) {
|
|
1015
|
+
const result = { isValid: true, reason: [] };
|
|
1016
|
+
method = method.toLocaleLowerCase();
|
|
1017
|
+
// validate method and path
|
|
1018
|
+
const methodAndPathResult = this.validateMethodAndPath(method, path);
|
|
1019
|
+
if (!methodAndPathResult.isValid) {
|
|
1020
|
+
return methodAndPathResult;
|
|
1021
|
+
}
|
|
1022
|
+
const operationObject = this.spec.paths[path][method];
|
|
1023
|
+
// validate operationId
|
|
1024
|
+
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
1025
|
+
result.reason.push(exports.ErrorType.MissingOperationId);
|
|
1026
|
+
}
|
|
1027
|
+
// validate server
|
|
1028
|
+
const validateServerResult = this.validateServer(method, path);
|
|
1029
|
+
result.reason.push(...validateServerResult.reason);
|
|
1030
|
+
if (result.reason.length > 0) {
|
|
1031
|
+
result.isValid = false;
|
|
1032
|
+
}
|
|
1033
|
+
return result;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
class ValidatorFactory {
|
|
1038
|
+
static create(spec, options) {
|
|
1039
|
+
var _a;
|
|
1040
|
+
const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : exports.ProjectType.SME;
|
|
1041
|
+
switch (type) {
|
|
1042
|
+
case exports.ProjectType.SME:
|
|
1043
|
+
return new SMEValidator(spec, options);
|
|
1044
|
+
case exports.ProjectType.Copilot:
|
|
1045
|
+
return new CopilotValidator(spec, options);
|
|
1046
|
+
case exports.ProjectType.TeamsAi:
|
|
1047
|
+
return new TeamsAIValidator(spec, options);
|
|
1048
|
+
default:
|
|
1049
|
+
throw new Error(`Invalid project type: ${type}`);
|
|
761
1050
|
}
|
|
762
|
-
return safeRegistrationIdEnvName;
|
|
763
1051
|
}
|
|
764
1052
|
}
|
|
765
1053
|
|
|
766
1054
|
// Copyright (c) Microsoft Corporation.
|
|
767
1055
|
class SpecFilter {
|
|
768
|
-
static specFilter(filter, unResolveSpec, resolvedSpec,
|
|
1056
|
+
static specFilter(filter, unResolveSpec, resolvedSpec, options) {
|
|
1057
|
+
var _a;
|
|
769
1058
|
try {
|
|
770
1059
|
const newSpec = Object.assign({}, unResolveSpec);
|
|
771
1060
|
const newPaths = {};
|
|
772
1061
|
for (const filterItem of filter) {
|
|
773
1062
|
const [method, path] = filterItem.split(" ");
|
|
774
1063
|
const methodName = method.toLowerCase();
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1064
|
+
const pathObj = (_a = resolvedSpec.paths) === null || _a === void 0 ? void 0 : _a[path];
|
|
1065
|
+
if (ConstantString.AllOperationMethods.includes(methodName) &&
|
|
1066
|
+
pathObj &&
|
|
1067
|
+
pathObj[methodName]) {
|
|
1068
|
+
const validator = ValidatorFactory.create(resolvedSpec, options);
|
|
1069
|
+
const validateResult = validator.validateAPI(methodName, path);
|
|
1070
|
+
if (!validateResult.isValid) {
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
if (!newPaths[path]) {
|
|
1074
|
+
newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
|
|
1075
|
+
for (const m of ConstantString.AllOperationMethods) {
|
|
1076
|
+
delete newPaths[path][m];
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
|
|
1080
|
+
// Add the operationId if missing
|
|
1081
|
+
if (!newPaths[path][methodName].operationId) {
|
|
1082
|
+
newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
|
|
782
1083
|
}
|
|
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
1084
|
}
|
|
789
1085
|
}
|
|
790
1086
|
newSpec.paths = newPaths;
|
|
@@ -798,47 +1094,203 @@ class SpecFilter {
|
|
|
798
1094
|
|
|
799
1095
|
// Copyright (c) Microsoft Corporation.
|
|
800
1096
|
class ManifestUpdater {
|
|
801
|
-
static
|
|
1097
|
+
static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
|
|
1098
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1099
|
+
const manifest = yield fs__default['default'].readJSON(manifestPath);
|
|
1100
|
+
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
1101
|
+
manifest.plugins = [
|
|
1102
|
+
{
|
|
1103
|
+
file: apiPluginRelativePath,
|
|
1104
|
+
id: ConstantString.DefaultPluginId,
|
|
1105
|
+
},
|
|
1106
|
+
];
|
|
1107
|
+
const appName = this.removeEnvs(manifest.name.short);
|
|
1108
|
+
ManifestUpdater.updateManifestDescription(manifest, spec);
|
|
1109
|
+
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
1110
|
+
const apiPlugin = yield ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, options);
|
|
1111
|
+
return [manifest, apiPlugin];
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
static updateManifestDescription(manifest, spec) {
|
|
802
1115
|
var _a, _b;
|
|
1116
|
+
manifest.description = {
|
|
1117
|
+
short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
|
|
1118
|
+
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),
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
|
|
1122
|
+
let parameter;
|
|
1123
|
+
if (schema.type === "string" ||
|
|
1124
|
+
schema.type === "boolean" ||
|
|
1125
|
+
schema.type === "integer" ||
|
|
1126
|
+
schema.type === "number" ||
|
|
1127
|
+
schema.type === "array") {
|
|
1128
|
+
parameter = schema;
|
|
1129
|
+
}
|
|
1130
|
+
else {
|
|
1131
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), exports.ErrorType.UpdateManifestFailed);
|
|
1132
|
+
}
|
|
1133
|
+
return parameter;
|
|
1134
|
+
}
|
|
1135
|
+
static generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, options) {
|
|
1136
|
+
var _a, _b, _c, _d;
|
|
1137
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1138
|
+
const functions = [];
|
|
1139
|
+
const functionNames = [];
|
|
1140
|
+
const paths = spec.paths;
|
|
1141
|
+
for (const pathUrl in paths) {
|
|
1142
|
+
const pathItem = paths[pathUrl];
|
|
1143
|
+
if (pathItem) {
|
|
1144
|
+
const operations = pathItem;
|
|
1145
|
+
for (const method in operations) {
|
|
1146
|
+
if (options.allowMethods.includes(method)) {
|
|
1147
|
+
const operationItem = operations[method];
|
|
1148
|
+
if (operationItem) {
|
|
1149
|
+
const operationId = operationItem.operationId;
|
|
1150
|
+
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
1151
|
+
const paramObject = operationItem.parameters;
|
|
1152
|
+
const requestBody = operationItem.requestBody;
|
|
1153
|
+
const parameters = {
|
|
1154
|
+
type: "object",
|
|
1155
|
+
properties: {},
|
|
1156
|
+
required: [],
|
|
1157
|
+
};
|
|
1158
|
+
if (paramObject) {
|
|
1159
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
1160
|
+
const param = paramObject[i];
|
|
1161
|
+
const schema = param.schema;
|
|
1162
|
+
parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
|
|
1163
|
+
if (param.required) {
|
|
1164
|
+
parameters.required.push(param.name);
|
|
1165
|
+
}
|
|
1166
|
+
if (!parameters.properties[param.name].description) {
|
|
1167
|
+
parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
if (requestBody) {
|
|
1172
|
+
const requestJsonBody = requestBody.content["application/json"];
|
|
1173
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
1174
|
+
if (requestBodySchema.type === "object") {
|
|
1175
|
+
if (requestBodySchema.required) {
|
|
1176
|
+
parameters.required.push(...requestBodySchema.required);
|
|
1177
|
+
}
|
|
1178
|
+
for (const property in requestBodySchema.properties) {
|
|
1179
|
+
const schema = requestBodySchema.properties[property];
|
|
1180
|
+
parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
else {
|
|
1184
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
const funcObj = {
|
|
1188
|
+
name: operationId,
|
|
1189
|
+
description: description,
|
|
1190
|
+
parameters: parameters,
|
|
1191
|
+
};
|
|
1192
|
+
functions.push(funcObj);
|
|
1193
|
+
functionNames.push(operationId);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
let apiPlugin;
|
|
1200
|
+
if (yield fs__default['default'].pathExists(apiPluginFilePath)) {
|
|
1201
|
+
apiPlugin = yield fs__default['default'].readJSON(apiPluginFilePath);
|
|
1202
|
+
}
|
|
1203
|
+
else {
|
|
1204
|
+
apiPlugin = {
|
|
1205
|
+
schema_version: "v2",
|
|
1206
|
+
name_for_human: "",
|
|
1207
|
+
description_for_human: "",
|
|
1208
|
+
functions: [],
|
|
1209
|
+
runtimes: [],
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
apiPlugin.functions = apiPlugin.functions || [];
|
|
1213
|
+
for (const func of functions) {
|
|
1214
|
+
const index = (_c = apiPlugin.functions) === null || _c === void 0 ? void 0 : _c.findIndex((f) => f.name === func.name);
|
|
1215
|
+
if (index === -1) {
|
|
1216
|
+
apiPlugin.functions.push(func);
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
apiPlugin.functions[index] = func;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
apiPlugin.runtimes = apiPlugin.runtimes || [];
|
|
1223
|
+
const index = apiPlugin.runtimes.findIndex((runtime) => runtime.spec.url === specRelativePath);
|
|
1224
|
+
if (index === -1) {
|
|
1225
|
+
apiPlugin.runtimes.push({
|
|
1226
|
+
type: "OpenApi",
|
|
1227
|
+
auth: {
|
|
1228
|
+
type: "none",
|
|
1229
|
+
},
|
|
1230
|
+
spec: {
|
|
1231
|
+
url: specRelativePath,
|
|
1232
|
+
},
|
|
1233
|
+
run_for_functions: functionNames,
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
else {
|
|
1237
|
+
apiPlugin.runtimes[index].run_for_functions = functionNames;
|
|
1238
|
+
}
|
|
1239
|
+
if (!apiPlugin.name_for_human) {
|
|
1240
|
+
apiPlugin.name_for_human = appName;
|
|
1241
|
+
}
|
|
1242
|
+
if (!apiPlugin.description_for_human) {
|
|
1243
|
+
apiPlugin.description_for_human =
|
|
1244
|
+
(_d = spec.info.description) !== null && _d !== void 0 ? _d : "<Please add description of the plugin>";
|
|
1245
|
+
}
|
|
1246
|
+
return apiPlugin;
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
|
|
803
1250
|
return __awaiter(this, void 0, void 0, function* () {
|
|
804
1251
|
try {
|
|
805
1252
|
const originalManifest = yield fs__default['default'].readJSON(manifestPath);
|
|
806
1253
|
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
|
-
|
|
1254
|
+
updatedPart.composeExtensions = [];
|
|
1255
|
+
let warnings = [];
|
|
1256
|
+
if (options.projectType === exports.ProjectType.SME) {
|
|
1257
|
+
const updateResult = yield ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
|
|
1258
|
+
const commands = updateResult[0];
|
|
1259
|
+
warnings = updateResult[1];
|
|
1260
|
+
const composeExtension = {
|
|
1261
|
+
composeExtensionType: "apiBased",
|
|
1262
|
+
apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
|
|
1263
|
+
commands: commands,
|
|
1264
|
+
};
|
|
1265
|
+
if (authInfo) {
|
|
1266
|
+
const auth = authInfo.authScheme;
|
|
1267
|
+
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1268
|
+
const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
1269
|
+
composeExtension.authorization = {
|
|
1270
|
+
authType: "apiSecretServiceAuth",
|
|
1271
|
+
apiSecretServiceAuthConfiguration: {
|
|
1272
|
+
apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
|
|
1273
|
+
},
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
|
|
1277
|
+
const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
|
|
1278
|
+
composeExtension.authorization = {
|
|
1279
|
+
authType: "oAuth2.0",
|
|
1280
|
+
oAuthConfiguration: {
|
|
1281
|
+
oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
|
|
1282
|
+
},
|
|
1283
|
+
};
|
|
1284
|
+
updatedPart.webApplicationInfo = {
|
|
1285
|
+
id: "${{AAD_APP_CLIENT_ID}}",
|
|
1286
|
+
resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
835
1289
|
}
|
|
1290
|
+
updatedPart.composeExtensions = [composeExtension];
|
|
836
1291
|
}
|
|
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];
|
|
1292
|
+
updatedPart.description = originalManifest.description;
|
|
1293
|
+
ManifestUpdater.updateManifestDescription(updatedPart, spec);
|
|
842
1294
|
const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
|
|
843
1295
|
return [updatedManifest, warnings];
|
|
844
1296
|
}
|
|
@@ -847,7 +1299,8 @@ class ManifestUpdater {
|
|
|
847
1299
|
}
|
|
848
1300
|
});
|
|
849
1301
|
}
|
|
850
|
-
static generateCommands(spec,
|
|
1302
|
+
static generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
|
|
1303
|
+
var _a;
|
|
851
1304
|
return __awaiter(this, void 0, void 0, function* () {
|
|
852
1305
|
const paths = spec.paths;
|
|
853
1306
|
const commands = [];
|
|
@@ -859,16 +1312,28 @@ class ManifestUpdater {
|
|
|
859
1312
|
const operations = pathItem;
|
|
860
1313
|
// Currently only support GET and POST method
|
|
861
1314
|
for (const method in operations) {
|
|
862
|
-
if (
|
|
1315
|
+
if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
|
|
863
1316
|
const operationItem = operations[method];
|
|
864
1317
|
if (operationItem) {
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1318
|
+
const command = Utils.parseApiInfo(operationItem, options);
|
|
1319
|
+
if (command.parameters &&
|
|
1320
|
+
command.parameters.length >= 1 &&
|
|
1321
|
+
command.parameters.some((param) => param.isRequired)) {
|
|
1322
|
+
command.parameters = command.parameters.filter((param) => param.isRequired);
|
|
1323
|
+
}
|
|
1324
|
+
else if (command.parameters && command.parameters.length > 0) {
|
|
1325
|
+
command.parameters = [command.parameters[0]];
|
|
1326
|
+
warnings.push({
|
|
1327
|
+
type: exports.WarningType.OperationOnlyContainsOptionalParam,
|
|
1328
|
+
content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
|
|
1329
|
+
data: command.id,
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
if (adaptiveCardFolder) {
|
|
1333
|
+
const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
|
|
1334
|
+
command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
|
|
1335
|
+
? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
|
|
1336
|
+
: "";
|
|
872
1337
|
}
|
|
873
1338
|
commands.push(command);
|
|
874
1339
|
}
|
|
@@ -884,13 +1349,22 @@ class ManifestUpdater {
|
|
|
884
1349
|
const relativePath = path__default['default'].relative(path__default['default'].dirname(from), to);
|
|
885
1350
|
return path__default['default'].normalize(relativePath).replace(/\\/g, "/");
|
|
886
1351
|
}
|
|
1352
|
+
static removeEnvs(str) {
|
|
1353
|
+
const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
|
|
1354
|
+
const matches = placeHolderReg.exec(str);
|
|
1355
|
+
let newStr = str;
|
|
1356
|
+
if (matches != null) {
|
|
1357
|
+
newStr = newStr.replace(matches[0], "");
|
|
1358
|
+
}
|
|
1359
|
+
return newStr;
|
|
1360
|
+
}
|
|
887
1361
|
}
|
|
888
1362
|
|
|
889
1363
|
// Copyright (c) Microsoft Corporation.
|
|
890
1364
|
class AdaptiveCardGenerator {
|
|
891
1365
|
static generateAdaptiveCard(operationItem) {
|
|
892
1366
|
try {
|
|
893
|
-
const json = Utils.getResponseJson(operationItem);
|
|
1367
|
+
const { json } = Utils.getResponseJson(operationItem);
|
|
894
1368
|
let cardBody = [];
|
|
895
1369
|
let schema = json.schema;
|
|
896
1370
|
let jsonPath = "$";
|
|
@@ -1150,8 +1624,11 @@ class SpecParser {
|
|
|
1150
1624
|
allowMissingId: true,
|
|
1151
1625
|
allowSwagger: true,
|
|
1152
1626
|
allowAPIKeyAuth: false,
|
|
1627
|
+
allowBearerTokenAuth: false,
|
|
1153
1628
|
allowMultipleParameters: false,
|
|
1154
1629
|
allowOauth2: false,
|
|
1630
|
+
allowMethods: ["get", "post"],
|
|
1631
|
+
projectType: exports.ProjectType.SME,
|
|
1155
1632
|
};
|
|
1156
1633
|
this.pathOrSpec = pathOrDoc;
|
|
1157
1634
|
this.parser = new SwaggerParser__default['default']();
|
|
@@ -1176,6 +1653,8 @@ class SpecParser {
|
|
|
1176
1653
|
errors: [{ type: exports.ErrorType.SpecNotValid, content: e.toString() }],
|
|
1177
1654
|
};
|
|
1178
1655
|
}
|
|
1656
|
+
const errors = [];
|
|
1657
|
+
const warnings = [];
|
|
1179
1658
|
if (!this.options.allowSwagger && this.isSwaggerFile) {
|
|
1180
1659
|
return {
|
|
1181
1660
|
status: exports.ValidationStatus.Error,
|
|
@@ -1185,7 +1664,38 @@ class SpecParser {
|
|
|
1185
1664
|
],
|
|
1186
1665
|
};
|
|
1187
1666
|
}
|
|
1188
|
-
|
|
1667
|
+
// Remote reference not supported
|
|
1668
|
+
const refPaths = this.parser.$refs.paths();
|
|
1669
|
+
// refPaths [0] is the current spec file path
|
|
1670
|
+
if (refPaths.length > 1) {
|
|
1671
|
+
errors.push({
|
|
1672
|
+
type: exports.ErrorType.RemoteRefNotSupported,
|
|
1673
|
+
content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
|
|
1674
|
+
data: refPaths,
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
if (!!this.isSwaggerFile && this.options.allowSwagger) {
|
|
1678
|
+
warnings.push({
|
|
1679
|
+
type: exports.WarningType.ConvertSwaggerToOpenAPI,
|
|
1680
|
+
content: ConstantString.ConvertSwaggerToOpenAPI,
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
const validator = this.getValidator(this.spec);
|
|
1684
|
+
const validationResult = validator.validateSpec();
|
|
1685
|
+
warnings.push(...validationResult.warnings);
|
|
1686
|
+
errors.push(...validationResult.errors);
|
|
1687
|
+
let status = exports.ValidationStatus.Valid;
|
|
1688
|
+
if (warnings.length > 0 && errors.length === 0) {
|
|
1689
|
+
status = exports.ValidationStatus.Warning;
|
|
1690
|
+
}
|
|
1691
|
+
else if (errors.length > 0) {
|
|
1692
|
+
status = exports.ValidationStatus.Error;
|
|
1693
|
+
}
|
|
1694
|
+
return {
|
|
1695
|
+
status: status,
|
|
1696
|
+
warnings: warnings,
|
|
1697
|
+
errors: errors,
|
|
1698
|
+
};
|
|
1189
1699
|
}
|
|
1190
1700
|
catch (err) {
|
|
1191
1701
|
throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
|
|
@@ -1209,39 +1719,40 @@ class SpecParser {
|
|
|
1209
1719
|
try {
|
|
1210
1720
|
yield this.loadSpec();
|
|
1211
1721
|
const spec = this.spec;
|
|
1212
|
-
const apiMap = this.
|
|
1213
|
-
const result =
|
|
1722
|
+
const apiMap = this.getAPIs(spec);
|
|
1723
|
+
const result = {
|
|
1724
|
+
APIs: [],
|
|
1725
|
+
allAPICount: 0,
|
|
1726
|
+
validAPICount: 0,
|
|
1727
|
+
};
|
|
1214
1728
|
for (const apiKey in apiMap) {
|
|
1729
|
+
const { operation, isValid, reason } = apiMap[apiKey];
|
|
1730
|
+
const [method, path] = apiKey.split(" ");
|
|
1731
|
+
const operationId = (_a = operation.operationId) !== null && _a !== void 0 ? _a : `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
|
|
1215
1732
|
const apiResult = {
|
|
1216
|
-
api:
|
|
1733
|
+
api: apiKey,
|
|
1217
1734
|
server: "",
|
|
1218
|
-
operationId:
|
|
1735
|
+
operationId: operationId,
|
|
1736
|
+
isValid: isValid,
|
|
1737
|
+
reason: reason,
|
|
1219
1738
|
};
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
if (!operationId) {
|
|
1232
|
-
operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
|
|
1233
|
-
}
|
|
1234
|
-
apiResult.operationId = operationId;
|
|
1235
|
-
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1236
|
-
for (const auths of authArray) {
|
|
1237
|
-
if (auths.length === 1) {
|
|
1238
|
-
apiResult.auth = auths[0].authSchema;
|
|
1239
|
-
break;
|
|
1739
|
+
if (isValid) {
|
|
1740
|
+
const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
|
|
1741
|
+
if (serverObj) {
|
|
1742
|
+
apiResult.server = Utils.resolveEnv(serverObj.url);
|
|
1743
|
+
}
|
|
1744
|
+
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1745
|
+
for (const auths of authArray) {
|
|
1746
|
+
if (auths.length === 1) {
|
|
1747
|
+
apiResult.auth = auths[0];
|
|
1748
|
+
break;
|
|
1749
|
+
}
|
|
1240
1750
|
}
|
|
1241
1751
|
}
|
|
1242
|
-
apiResult
|
|
1243
|
-
result.push(apiResult);
|
|
1752
|
+
result.APIs.push(apiResult);
|
|
1244
1753
|
}
|
|
1754
|
+
result.allAPICount = result.APIs.length;
|
|
1755
|
+
result.validAPICount = result.APIs.filter((api) => api.isValid).length;
|
|
1245
1756
|
return result;
|
|
1246
1757
|
}
|
|
1247
1758
|
catch (err) {
|
|
@@ -1252,49 +1763,113 @@ class SpecParser {
|
|
|
1252
1763
|
}
|
|
1253
1764
|
});
|
|
1254
1765
|
}
|
|
1766
|
+
/**
|
|
1767
|
+
* Generate specs according to the filters.
|
|
1768
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1769
|
+
*/
|
|
1770
|
+
getFilteredSpecs(filter, signal) {
|
|
1771
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1772
|
+
try {
|
|
1773
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1774
|
+
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1775
|
+
}
|
|
1776
|
+
yield this.loadSpec();
|
|
1777
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1778
|
+
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1779
|
+
}
|
|
1780
|
+
const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
|
|
1781
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1782
|
+
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1783
|
+
}
|
|
1784
|
+
const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
|
|
1785
|
+
return [newUnResolvedSpec, newSpec];
|
|
1786
|
+
}
|
|
1787
|
+
catch (err) {
|
|
1788
|
+
if (err instanceof SpecParserError) {
|
|
1789
|
+
throw err;
|
|
1790
|
+
}
|
|
1791
|
+
throw new SpecParserError(err.toString(), exports.ErrorType.GetSpecFailed);
|
|
1792
|
+
}
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1255
1795
|
/**
|
|
1256
1796
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
1257
1797
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
1258
1798
|
* @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
1799
|
* @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
|
|
1800
|
+
* @param pluginFilePath File path of the api plugin file to generate.
|
|
1261
1801
|
*/
|
|
1262
|
-
|
|
1802
|
+
generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
1263
1803
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1264
1804
|
const result = {
|
|
1265
1805
|
allSuccess: true,
|
|
1266
1806
|
warnings: [],
|
|
1267
1807
|
};
|
|
1268
1808
|
try {
|
|
1269
|
-
|
|
1270
|
-
|
|
1809
|
+
const newSpecs = yield this.getFilteredSpecs(filter, signal);
|
|
1810
|
+
const newUnResolvedSpec = newSpecs[0];
|
|
1811
|
+
const newSpec = newSpecs[1];
|
|
1812
|
+
let resultStr;
|
|
1813
|
+
if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
|
|
1814
|
+
resultStr = jsyaml__default['default'].dump(newUnResolvedSpec);
|
|
1271
1815
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1816
|
+
else {
|
|
1817
|
+
resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
|
|
1275
1818
|
}
|
|
1276
|
-
|
|
1819
|
+
yield fs__default['default'].outputFile(outputSpecPath, resultStr);
|
|
1277
1820
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1278
1821
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1279
1822
|
}
|
|
1280
|
-
const
|
|
1281
|
-
|
|
1282
|
-
|
|
1823
|
+
const [updatedManifest, apiPlugin] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
|
|
1824
|
+
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1825
|
+
yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
|
|
1826
|
+
}
|
|
1827
|
+
catch (err) {
|
|
1828
|
+
if (err instanceof SpecParserError) {
|
|
1829
|
+
throw err;
|
|
1830
|
+
}
|
|
1831
|
+
throw new SpecParserError(err.toString(), exports.ErrorType.GenerateFailed);
|
|
1832
|
+
}
|
|
1833
|
+
return result;
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
1838
|
+
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
1839
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1840
|
+
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
1841
|
+
* @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
|
|
1842
|
+
*/
|
|
1843
|
+
generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
1844
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1845
|
+
const result = {
|
|
1846
|
+
allSuccess: true,
|
|
1847
|
+
warnings: [],
|
|
1848
|
+
};
|
|
1849
|
+
try {
|
|
1850
|
+
const newSpecs = yield this.getFilteredSpecs(filter, signal);
|
|
1851
|
+
const newUnResolvedSpec = newSpecs[0];
|
|
1852
|
+
const newSpec = newSpecs[1];
|
|
1853
|
+
let hasMultipleAuth = false;
|
|
1854
|
+
let authInfo = undefined;
|
|
1283
1855
|
for (const url in newSpec.paths) {
|
|
1284
1856
|
for (const method in newSpec.paths[url]) {
|
|
1285
1857
|
const operation = newSpec.paths[url][method];
|
|
1286
1858
|
const authArray = Utils.getAuthArray(operation.security, newSpec);
|
|
1287
1859
|
if (authArray && authArray.length > 0) {
|
|
1288
|
-
|
|
1289
|
-
if (
|
|
1290
|
-
|
|
1860
|
+
const currentAuth = authArray[0][0];
|
|
1861
|
+
if (!authInfo) {
|
|
1862
|
+
authInfo = authArray[0][0];
|
|
1863
|
+
}
|
|
1864
|
+
else if (authInfo.name !== currentAuth.name) {
|
|
1865
|
+
hasMultipleAuth = true;
|
|
1291
1866
|
break;
|
|
1292
1867
|
}
|
|
1293
1868
|
}
|
|
1294
1869
|
}
|
|
1295
1870
|
}
|
|
1296
|
-
if (
|
|
1297
|
-
throw new SpecParserError(ConstantString.
|
|
1871
|
+
if (hasMultipleAuth && this.options.projectType !== exports.ProjectType.TeamsAi) {
|
|
1872
|
+
throw new SpecParserError(ConstantString.MultipleAuthNotSupported, exports.ErrorType.MultipleAuthNotSupported);
|
|
1298
1873
|
}
|
|
1299
1874
|
let resultStr;
|
|
1300
1875
|
if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
|
|
@@ -1304,26 +1879,28 @@ class SpecParser {
|
|
|
1304
1879
|
resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
|
|
1305
1880
|
}
|
|
1306
1881
|
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
|
-
|
|
1882
|
+
if (adaptiveCardFolder) {
|
|
1883
|
+
for (const url in newSpec.paths) {
|
|
1884
|
+
for (const method in newSpec.paths[url]) {
|
|
1885
|
+
// paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
|
|
1886
|
+
if (this.options.allowMethods.includes(method)) {
|
|
1887
|
+
const operation = newSpec.paths[url][method];
|
|
1888
|
+
try {
|
|
1889
|
+
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
1890
|
+
const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
|
|
1891
|
+
const wrappedCard = wrapAdaptiveCard(card, jsonPath);
|
|
1892
|
+
yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
|
|
1893
|
+
const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
|
|
1894
|
+
yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
|
|
1895
|
+
}
|
|
1896
|
+
catch (err) {
|
|
1897
|
+
result.allSuccess = false;
|
|
1898
|
+
result.warnings.push({
|
|
1899
|
+
type: exports.WarningType.GenerateCardFailed,
|
|
1900
|
+
content: err.toString(),
|
|
1901
|
+
data: operation.operationId,
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1327
1904
|
}
|
|
1328
1905
|
}
|
|
1329
1906
|
}
|
|
@@ -1331,8 +1908,7 @@ class SpecParser {
|
|
|
1331
1908
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1332
1909
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1333
1910
|
}
|
|
1334
|
-
const
|
|
1335
|
-
const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth);
|
|
1911
|
+
const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
|
|
1336
1912
|
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1337
1913
|
result.warnings.push(...warnings);
|
|
1338
1914
|
}
|
|
@@ -1360,16 +1936,23 @@ class SpecParser {
|
|
|
1360
1936
|
}
|
|
1361
1937
|
});
|
|
1362
1938
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1939
|
+
getAPIs(spec) {
|
|
1940
|
+
const validator = this.getValidator(spec);
|
|
1941
|
+
const apiMap = validator.listAPIs();
|
|
1942
|
+
this.apiMap = apiMap;
|
|
1943
|
+
return apiMap;
|
|
1944
|
+
}
|
|
1945
|
+
getValidator(spec) {
|
|
1946
|
+
if (this.validator) {
|
|
1947
|
+
return this.validator;
|
|
1366
1948
|
}
|
|
1367
|
-
const
|
|
1368
|
-
this.
|
|
1369
|
-
return
|
|
1949
|
+
const validator = ValidatorFactory.create(spec, this.options);
|
|
1950
|
+
this.validator = validator;
|
|
1951
|
+
return validator;
|
|
1370
1952
|
}
|
|
1371
1953
|
}
|
|
1372
1954
|
|
|
1955
|
+
exports.AdaptiveCardGenerator = AdaptiveCardGenerator;
|
|
1373
1956
|
exports.ConstantString = ConstantString;
|
|
1374
1957
|
exports.SpecParser = SpecParser;
|
|
1375
1958
|
exports.SpecParserError = SpecParserError;
|