@microsoft/m365-spec-parser 0.1.1-alpha.7fe3da414.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 +537 -357
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +611 -391
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +537 -357
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +767 -545
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/interfaces.d.ts +14 -0
- package/dist/src/manifestUpdater.d.ts +1 -1
- package/dist/src/specParser.browser.d.ts +3 -2
- package/dist/src/specParser.d.ts +2 -0
- package/dist/src/utils.d.ts +4 -25
- package/package.json +3 -3
package/dist/index.node.cjs.js
CHANGED
|
@@ -208,7 +208,8 @@ ConstantString.CommandDescriptionMaxLens = 128;
|
|
|
208
208
|
ConstantString.ParameterDescriptionMaxLens = 128;
|
|
209
209
|
ConstantString.CommandTitleMaxLens = 32;
|
|
210
210
|
ConstantString.ParameterTitleMaxLens = 32;
|
|
211
|
-
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
211
|
+
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
212
|
+
ConstantString.DefaultPluginId = "plugin_1";
|
|
212
213
|
|
|
213
214
|
// Copyright (c) Microsoft Corporation.
|
|
214
215
|
class SpecParserError extends Error {
|
|
@@ -231,249 +232,9 @@ class Utils {
|
|
|
231
232
|
}
|
|
232
233
|
return false;
|
|
233
234
|
}
|
|
234
|
-
static checkParameters(paramObject, isCopilot) {
|
|
235
|
-
const paramResult = {
|
|
236
|
-
requiredNum: 0,
|
|
237
|
-
optionalNum: 0,
|
|
238
|
-
isValid: true,
|
|
239
|
-
reason: [],
|
|
240
|
-
};
|
|
241
|
-
if (!paramObject) {
|
|
242
|
-
return paramResult;
|
|
243
|
-
}
|
|
244
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
245
|
-
const param = paramObject[i];
|
|
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
|
-
}
|
|
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
|
-
}
|
|
262
|
-
if (param.in === "header" || param.in === "cookie") {
|
|
263
|
-
if (isRequiredWithoutDefault) {
|
|
264
|
-
paramResult.isValid = false;
|
|
265
|
-
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
266
|
-
}
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
if (schema.type !== "boolean" &&
|
|
270
|
-
schema.type !== "string" &&
|
|
271
|
-
schema.type !== "number" &&
|
|
272
|
-
schema.type !== "integer") {
|
|
273
|
-
if (isRequiredWithoutDefault) {
|
|
274
|
-
paramResult.isValid = false;
|
|
275
|
-
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
276
|
-
}
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
279
|
-
if (param.in === "query" || param.in === "path") {
|
|
280
|
-
if (isRequiredWithoutDefault) {
|
|
281
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return paramResult;
|
|
289
|
-
}
|
|
290
|
-
static checkPostBody(schema, isRequired = false, isCopilot = false) {
|
|
291
|
-
var _a;
|
|
292
|
-
const paramResult = {
|
|
293
|
-
requiredNum: 0,
|
|
294
|
-
optionalNum: 0,
|
|
295
|
-
isValid: true,
|
|
296
|
-
reason: [],
|
|
297
|
-
};
|
|
298
|
-
if (Object.keys(schema).length === 0) {
|
|
299
|
-
return paramResult;
|
|
300
|
-
}
|
|
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
|
-
}
|
|
307
|
-
if (schema.type === "string" ||
|
|
308
|
-
schema.type === "integer" ||
|
|
309
|
-
schema.type === "boolean" ||
|
|
310
|
-
schema.type === "number") {
|
|
311
|
-
if (isRequiredWithoutDefault) {
|
|
312
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
313
|
-
}
|
|
314
|
-
else {
|
|
315
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
else if (schema.type === "object") {
|
|
319
|
-
const { properties } = schema;
|
|
320
|
-
for (const property in properties) {
|
|
321
|
-
let isRequired = false;
|
|
322
|
-
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
323
|
-
isRequired = true;
|
|
324
|
-
}
|
|
325
|
-
const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
|
|
326
|
-
paramResult.requiredNum += result.requiredNum;
|
|
327
|
-
paramResult.optionalNum += result.optionalNum;
|
|
328
|
-
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
329
|
-
paramResult.reason.push(...result.reason);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
else {
|
|
333
|
-
if (isRequiredWithoutDefault && !isCopilot) {
|
|
334
|
-
paramResult.isValid = false;
|
|
335
|
-
paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return paramResult;
|
|
339
|
-
}
|
|
340
235
|
static containMultipleMediaTypes(bodyObject) {
|
|
341
236
|
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
342
237
|
}
|
|
343
|
-
/**
|
|
344
|
-
* Checks if the given API is supported.
|
|
345
|
-
* @param {string} method - The HTTP method of the API.
|
|
346
|
-
* @param {string} path - The path of the API.
|
|
347
|
-
* @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
|
|
348
|
-
* @returns {boolean} - Returns true if the API is supported, false otherwise.
|
|
349
|
-
* @description The following APIs are supported:
|
|
350
|
-
* 1. only support Get/Post operation without auth property
|
|
351
|
-
* 2. parameter inside query or path only support string, number, boolean and integer
|
|
352
|
-
* 3. parameter inside post body only support string, number, boolean, integer and object
|
|
353
|
-
* 4. request body + required parameters <= 1
|
|
354
|
-
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
355
|
-
* 6. only support request body with “application/json” content type
|
|
356
|
-
*/
|
|
357
|
-
static isSupportedApi(method, path, spec, options) {
|
|
358
|
-
var _a;
|
|
359
|
-
const result = { isValid: true, reason: [] };
|
|
360
|
-
method = method.toLocaleLowerCase();
|
|
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);
|
|
423
|
-
}
|
|
424
|
-
requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
|
|
425
|
-
if (!requestBodyParamResult.isValid && requestBodyParamResult.reason) {
|
|
426
|
-
result.reason.push(...requestBodyParamResult.reason);
|
|
427
|
-
}
|
|
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);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
else if (totalParams === 0) {
|
|
444
|
-
result.reason.push(exports.ErrorType.NoParameter);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
if (result.reason.length > 0) {
|
|
449
|
-
result.isValid = false;
|
|
450
|
-
}
|
|
451
|
-
return result;
|
|
452
|
-
}
|
|
453
|
-
static isSupportedAuth(authSchemeArray, options) {
|
|
454
|
-
if (authSchemeArray.length === 0) {
|
|
455
|
-
return { isValid: true, reason: [] };
|
|
456
|
-
}
|
|
457
|
-
if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
|
|
458
|
-
// Currently we don't support multiple auth in one operation
|
|
459
|
-
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
460
|
-
return {
|
|
461
|
-
isValid: false,
|
|
462
|
-
reason: [exports.ErrorType.MultipleAuthNotSupported],
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
for (const auths of authSchemeArray) {
|
|
466
|
-
if (auths.length === 1) {
|
|
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: [] };
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
|
|
476
|
-
}
|
|
477
238
|
static isBearerTokenAuth(authScheme) {
|
|
478
239
|
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
479
240
|
}
|
|
@@ -481,10 +242,9 @@ class Utils {
|
|
|
481
242
|
return authScheme.type === "apiKey";
|
|
482
243
|
}
|
|
483
244
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
return false;
|
|
245
|
+
return !!(authScheme.type === "oauth2" &&
|
|
246
|
+
authScheme.flows &&
|
|
247
|
+
authScheme.flows.authorizationCode);
|
|
488
248
|
}
|
|
489
249
|
static getAuthArray(securities, spec) {
|
|
490
250
|
var _a;
|
|
@@ -512,7 +272,7 @@ class Utils {
|
|
|
512
272
|
static updateFirstLetter(str) {
|
|
513
273
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
514
274
|
}
|
|
515
|
-
static getResponseJson(operationObject
|
|
275
|
+
static getResponseJson(operationObject) {
|
|
516
276
|
var _a, _b;
|
|
517
277
|
let json = {};
|
|
518
278
|
let multipleMediaType = false;
|
|
@@ -523,9 +283,6 @@ class Utils {
|
|
|
523
283
|
json = responseObject.content["application/json"];
|
|
524
284
|
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
525
285
|
multipleMediaType = true;
|
|
526
|
-
if (isTeamsAiProject) {
|
|
527
|
-
break;
|
|
528
|
-
}
|
|
529
286
|
json = {};
|
|
530
287
|
}
|
|
531
288
|
else {
|
|
@@ -675,216 +432,622 @@ class Utils {
|
|
|
675
432
|
else {
|
|
676
433
|
optionalParams.push(parameter);
|
|
677
434
|
}
|
|
678
|
-
}
|
|
679
|
-
else if (schema.type === "object") {
|
|
680
|
-
const { properties } = schema;
|
|
681
|
-
for (const property in properties) {
|
|
682
|
-
let isRequired = false;
|
|
683
|
-
if (schema.required && ((_b = schema.required) === null || _b === void 0 ? void 0 : _b.indexOf(property)) >= 0) {
|
|
684
|
-
isRequired = true;
|
|
435
|
+
}
|
|
436
|
+
else if (schema.type === "object") {
|
|
437
|
+
const { properties } = schema;
|
|
438
|
+
for (const property in properties) {
|
|
439
|
+
let isRequired = false;
|
|
440
|
+
if (schema.required && ((_b = schema.required) === null || _b === void 0 ? void 0 : _b.indexOf(property)) >= 0) {
|
|
441
|
+
isRequired = true;
|
|
442
|
+
}
|
|
443
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(properties[property], property, allowMultipleParameters, isRequired);
|
|
444
|
+
requiredParams.push(...requiredP);
|
|
445
|
+
optionalParams.push(...optionalP);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return [requiredParams, optionalParams];
|
|
449
|
+
}
|
|
450
|
+
static updateParameterWithInputType(schema, param) {
|
|
451
|
+
if (schema.enum) {
|
|
452
|
+
param.inputType = "choiceset";
|
|
453
|
+
param.choices = [];
|
|
454
|
+
for (let i = 0; i < schema.enum.length; i++) {
|
|
455
|
+
param.choices.push({
|
|
456
|
+
title: schema.enum[i],
|
|
457
|
+
value: schema.enum[i],
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
else if (schema.type === "string") {
|
|
462
|
+
param.inputType = "text";
|
|
463
|
+
}
|
|
464
|
+
else if (schema.type === "integer" || schema.type === "number") {
|
|
465
|
+
param.inputType = "number";
|
|
466
|
+
}
|
|
467
|
+
else if (schema.type === "boolean") {
|
|
468
|
+
param.inputType = "toggle";
|
|
469
|
+
}
|
|
470
|
+
if (schema.default) {
|
|
471
|
+
param.value = schema.default;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
static parseApiInfo(operationItem, options) {
|
|
475
|
+
var _a, _b;
|
|
476
|
+
const requiredParams = [];
|
|
477
|
+
const optionalParams = [];
|
|
478
|
+
const paramObject = operationItem.parameters;
|
|
479
|
+
if (paramObject) {
|
|
480
|
+
paramObject.forEach((param) => {
|
|
481
|
+
var _a;
|
|
482
|
+
const parameter = {
|
|
483
|
+
name: param.name,
|
|
484
|
+
title: Utils.updateFirstLetter(param.name).slice(0, ConstantString.ParameterTitleMaxLens),
|
|
485
|
+
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
486
|
+
};
|
|
487
|
+
const schema = param.schema;
|
|
488
|
+
if (options.allowMultipleParameters && schema) {
|
|
489
|
+
Utils.updateParameterWithInputType(schema, parameter);
|
|
490
|
+
}
|
|
491
|
+
if (param.in !== "header" && param.in !== "cookie") {
|
|
492
|
+
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
493
|
+
parameter.isRequired = true;
|
|
494
|
+
requiredParams.push(parameter);
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
optionalParams.push(parameter);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
if (operationItem.requestBody) {
|
|
503
|
+
const requestBody = operationItem.requestBody;
|
|
504
|
+
const requestJson = requestBody.content["application/json"];
|
|
505
|
+
if (Object.keys(requestJson).length !== 0) {
|
|
506
|
+
const schema = requestJson.schema;
|
|
507
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
508
|
+
requiredParams.push(...requiredP);
|
|
509
|
+
optionalParams.push(...optionalP);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const operationId = operationItem.operationId;
|
|
513
|
+
const parameters = [...requiredParams, ...optionalParams];
|
|
514
|
+
const command = {
|
|
515
|
+
context: ["compose"],
|
|
516
|
+
type: "query",
|
|
517
|
+
title: ((_a = operationItem.summary) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.CommandTitleMaxLens),
|
|
518
|
+
id: operationId,
|
|
519
|
+
parameters: parameters,
|
|
520
|
+
description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
|
|
521
|
+
};
|
|
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;
|
|
538
|
+
}
|
|
539
|
+
return safeRegistrationIdEnvName;
|
|
540
|
+
}
|
|
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;
|
|
560
|
+
const result = {};
|
|
561
|
+
for (const path in paths) {
|
|
562
|
+
const methods = paths[path];
|
|
563
|
+
for (const method in methods) {
|
|
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
|
+
};
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
this.apiMap = result;
|
|
576
|
+
return result;
|
|
577
|
+
}
|
|
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,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
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({
|
|
607
|
+
type: exports.ErrorType.NoSupportedApi,
|
|
608
|
+
content: ConstantString.NoSupportedApi,
|
|
609
|
+
data,
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
return result;
|
|
613
|
+
}
|
|
614
|
+
validateSpecOperationId() {
|
|
615
|
+
const result = { errors: [], warnings: [] };
|
|
616
|
+
const apiMap = this.listAPIs();
|
|
617
|
+
// OperationId missing
|
|
618
|
+
const apisMissingOperationId = [];
|
|
619
|
+
for (const key in apiMap) {
|
|
620
|
+
const { operation } = apiMap[key];
|
|
621
|
+
if (!operation.operationId) {
|
|
622
|
+
apisMissingOperationId.push(key);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
if (apisMissingOperationId.length > 0) {
|
|
626
|
+
result.warnings.push({
|
|
627
|
+
type: exports.WarningType.OperationIdMissing,
|
|
628
|
+
content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
|
|
629
|
+
data: apisMissingOperationId,
|
|
630
|
+
});
|
|
631
|
+
}
|
|
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));
|
|
674
|
+
}
|
|
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: [] };
|
|
684
|
+
}
|
|
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: [],
|
|
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;
|
|
757
|
+
}
|
|
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;
|
|
685
810
|
}
|
|
686
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(properties[property], property, allowMultipleParameters, isRequired);
|
|
687
|
-
requiredParams.push(...requiredP);
|
|
688
|
-
optionalParams.push(...optionalP);
|
|
689
811
|
}
|
|
690
812
|
}
|
|
691
|
-
return
|
|
813
|
+
return paramResult;
|
|
692
814
|
}
|
|
693
|
-
|
|
694
|
-
if (schema.
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
value: schema.enum[i],
|
|
701
|
-
});
|
|
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
|
+
}
|
|
702
822
|
}
|
|
703
823
|
}
|
|
704
|
-
|
|
705
|
-
param.inputType = "text";
|
|
706
|
-
}
|
|
707
|
-
else if (schema.type === "integer" || schema.type === "number") {
|
|
708
|
-
param.inputType = "number";
|
|
709
|
-
}
|
|
710
|
-
else if (schema.type === "boolean") {
|
|
711
|
-
param.inputType = "toggle";
|
|
712
|
-
}
|
|
713
|
-
if (schema.default) {
|
|
714
|
-
param.value = schema.default;
|
|
715
|
-
}
|
|
824
|
+
return false;
|
|
716
825
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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);
|
|
754
867
|
}
|
|
755
|
-
|
|
756
|
-
const
|
|
757
|
-
|
|
758
|
-
|
|
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);
|
|
759
879
|
}
|
|
760
|
-
|
|
761
|
-
|
|
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);
|
|
762
887
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
|
|
770
|
-
};
|
|
771
|
-
let warning = undefined;
|
|
772
|
-
if (requiredParams.length === 0 && optionalParams.length > 1) {
|
|
773
|
-
warning = {
|
|
774
|
-
type: exports.WarningType.OperationOnlyContainsOptionalParam,
|
|
775
|
-
content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
|
|
776
|
-
data: operationId,
|
|
777
|
-
};
|
|
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;
|
|
778
894
|
}
|
|
779
|
-
return
|
|
895
|
+
return result;
|
|
780
896
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
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);
|
|
798
922
|
}
|
|
799
923
|
return result;
|
|
800
924
|
}
|
|
801
|
-
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
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);
|
|
810
940
|
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
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);
|
|
822
958
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
type: exports.ErrorType.NoSupportedApi,
|
|
828
|
-
content: ConstantString.NoSupportedApi,
|
|
829
|
-
});
|
|
959
|
+
if (requestJsonBody) {
|
|
960
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
961
|
+
postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
962
|
+
result.reason.push(...postBodyResult.reason);
|
|
830
963
|
}
|
|
831
|
-
//
|
|
832
|
-
const
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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);
|
|
838
972
|
}
|
|
839
|
-
if (
|
|
840
|
-
|
|
841
|
-
type: exports.WarningType.OperationIdMissing,
|
|
842
|
-
content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
|
|
843
|
-
data: apisMissingOperationId,
|
|
844
|
-
});
|
|
973
|
+
if (result.reason.length > 0) {
|
|
974
|
+
result.isValid = false;
|
|
845
975
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
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
|
+
}
|
|
849
987
|
}
|
|
850
|
-
else if (
|
|
851
|
-
|
|
988
|
+
else if (totalParams === 0) {
|
|
989
|
+
result.reason.push(exports.ErrorType.NoParameter);
|
|
852
990
|
}
|
|
853
|
-
return
|
|
854
|
-
status,
|
|
855
|
-
warnings,
|
|
856
|
-
errors,
|
|
857
|
-
};
|
|
991
|
+
return result;
|
|
858
992
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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;
|
|
865
1003
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
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);
|
|
869
1026
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
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;
|
|
873
1032
|
}
|
|
874
|
-
return
|
|
1033
|
+
return result;
|
|
875
1034
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
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}`);
|
|
886
1050
|
}
|
|
887
|
-
return count;
|
|
888
1051
|
}
|
|
889
1052
|
}
|
|
890
1053
|
|
|
@@ -902,7 +1065,8 @@ class SpecFilter {
|
|
|
902
1065
|
if (ConstantString.AllOperationMethods.includes(methodName) &&
|
|
903
1066
|
pathObj &&
|
|
904
1067
|
pathObj[methodName]) {
|
|
905
|
-
const
|
|
1068
|
+
const validator = ValidatorFactory.create(resolvedSpec, options);
|
|
1069
|
+
const validateResult = validator.validateAPI(methodName, path);
|
|
906
1070
|
if (!validateResult.isValid) {
|
|
907
1071
|
continue;
|
|
908
1072
|
}
|
|
@@ -936,13 +1100,14 @@ class ManifestUpdater {
|
|
|
936
1100
|
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
937
1101
|
manifest.plugins = [
|
|
938
1102
|
{
|
|
939
|
-
|
|
1103
|
+
file: apiPluginRelativePath,
|
|
1104
|
+
id: ConstantString.DefaultPluginId,
|
|
940
1105
|
},
|
|
941
1106
|
];
|
|
942
1107
|
const appName = this.removeEnvs(manifest.name.short);
|
|
943
1108
|
ManifestUpdater.updateManifestDescription(manifest, spec);
|
|
944
1109
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
945
|
-
const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
|
|
1110
|
+
const apiPlugin = yield ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, options);
|
|
946
1111
|
return [manifest, apiPlugin];
|
|
947
1112
|
});
|
|
948
1113
|
}
|
|
@@ -967,88 +1132,119 @@ class ManifestUpdater {
|
|
|
967
1132
|
}
|
|
968
1133
|
return parameter;
|
|
969
1134
|
}
|
|
970
|
-
static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
|
|
971
|
-
var _a, _b, _c;
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
const
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
parameters.properties[param.name].description
|
|
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
|
+
}
|
|
1002
1169
|
}
|
|
1003
1170
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
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
|
+
}
|
|
1011
1182
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
|
|
1183
|
+
else {
|
|
1184
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
|
|
1015
1185
|
}
|
|
1016
1186
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1187
|
+
const funcObj = {
|
|
1188
|
+
name: operationId,
|
|
1189
|
+
description: description,
|
|
1190
|
+
parameters: parameters,
|
|
1191
|
+
};
|
|
1192
|
+
functions.push(funcObj);
|
|
1193
|
+
functionNames.push(operationId);
|
|
1020
1194
|
}
|
|
1021
|
-
const funcObj = {
|
|
1022
|
-
name: operationId,
|
|
1023
|
-
description: description,
|
|
1024
|
-
parameters: parameters,
|
|
1025
|
-
};
|
|
1026
|
-
functions.push(funcObj);
|
|
1027
|
-
functionNames.push(operationId);
|
|
1028
1195
|
}
|
|
1029
1196
|
}
|
|
1030
1197
|
}
|
|
1031
1198
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
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({
|
|
1040
1226
|
type: "OpenApi",
|
|
1041
1227
|
auth: {
|
|
1042
|
-
type: "none",
|
|
1228
|
+
type: "none",
|
|
1043
1229
|
},
|
|
1044
1230
|
spec: {
|
|
1045
1231
|
url: specRelativePath,
|
|
1046
1232
|
},
|
|
1047
1233
|
run_for_functions: functionNames,
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
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
|
+
});
|
|
1052
1248
|
}
|
|
1053
1249
|
static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
|
|
1054
1250
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1119,16 +1315,26 @@ class ManifestUpdater {
|
|
|
1119
1315
|
if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
|
|
1120
1316
|
const operationItem = operations[method];
|
|
1121
1317
|
if (operationItem) {
|
|
1122
|
-
const
|
|
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
|
+
}
|
|
1123
1332
|
if (adaptiveCardFolder) {
|
|
1124
1333
|
const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
|
|
1125
1334
|
command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
|
|
1126
1335
|
? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
|
|
1127
1336
|
: "";
|
|
1128
1337
|
}
|
|
1129
|
-
if (warning) {
|
|
1130
|
-
warnings.push(warning);
|
|
1131
|
-
}
|
|
1132
1338
|
commands.push(command);
|
|
1133
1339
|
}
|
|
1134
1340
|
}
|
|
@@ -1447,6 +1653,8 @@ class SpecParser {
|
|
|
1447
1653
|
errors: [{ type: exports.ErrorType.SpecNotValid, content: e.toString() }],
|
|
1448
1654
|
};
|
|
1449
1655
|
}
|
|
1656
|
+
const errors = [];
|
|
1657
|
+
const warnings = [];
|
|
1450
1658
|
if (!this.options.allowSwagger && this.isSwaggerFile) {
|
|
1451
1659
|
return {
|
|
1452
1660
|
status: exports.ValidationStatus.Error,
|
|
@@ -1456,23 +1664,38 @@ class SpecParser {
|
|
|
1456
1664
|
],
|
|
1457
1665
|
};
|
|
1458
1666
|
}
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
}
|
|
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;
|
|
1474
1690
|
}
|
|
1475
|
-
|
|
1691
|
+
else if (errors.length > 0) {
|
|
1692
|
+
status = exports.ValidationStatus.Error;
|
|
1693
|
+
}
|
|
1694
|
+
return {
|
|
1695
|
+
status: status,
|
|
1696
|
+
warnings: warnings,
|
|
1697
|
+
errors: errors,
|
|
1698
|
+
};
|
|
1476
1699
|
}
|
|
1477
1700
|
catch (err) {
|
|
1478
1701
|
throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
|
|
@@ -1505,34 +1728,27 @@ class SpecParser {
|
|
|
1505
1728
|
for (const apiKey in apiMap) {
|
|
1506
1729
|
const { operation, isValid, reason } = apiMap[apiKey];
|
|
1507
1730
|
const [method, path] = apiKey.split(" ");
|
|
1731
|
+
const operationId = (_a = operation.operationId) !== null && _a !== void 0 ? _a : `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
|
|
1508
1732
|
const apiResult = {
|
|
1509
|
-
api:
|
|
1733
|
+
api: apiKey,
|
|
1510
1734
|
server: "",
|
|
1511
|
-
operationId:
|
|
1735
|
+
operationId: operationId,
|
|
1512
1736
|
isValid: isValid,
|
|
1513
1737
|
reason: reason,
|
|
1514
1738
|
};
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
}
|
|
1527
|
-
apiResult.operationId = operationId;
|
|
1528
|
-
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1529
|
-
for (const auths of authArray) {
|
|
1530
|
-
if (auths.length === 1) {
|
|
1531
|
-
apiResult.auth = auths[0];
|
|
1532
|
-
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
|
+
}
|
|
1533
1750
|
}
|
|
1534
1751
|
}
|
|
1535
|
-
apiResult.api = apiKey;
|
|
1536
1752
|
result.APIs.push(apiResult);
|
|
1537
1753
|
}
|
|
1538
1754
|
result.allAPICount = result.APIs.length;
|
|
@@ -1721,12 +1937,18 @@ class SpecParser {
|
|
|
1721
1937
|
});
|
|
1722
1938
|
}
|
|
1723
1939
|
getAPIs(spec) {
|
|
1724
|
-
|
|
1725
|
-
|
|
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;
|
|
1726
1948
|
}
|
|
1727
|
-
const
|
|
1728
|
-
this.
|
|
1729
|
-
return
|
|
1949
|
+
const validator = ValidatorFactory.create(spec, this.options);
|
|
1950
|
+
this.validator = validator;
|
|
1951
|
+
return validator;
|
|
1730
1952
|
}
|
|
1731
1953
|
}
|
|
1732
1954
|
|