@microsoft/m365-spec-parser 0.1.1-alpha.a277dba4e.0 → 0.1.1-alpha.b015b287e.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 +170 -113
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +214 -141
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +170 -113
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +214 -141
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/interfaces.d.ts +30 -1
- package/dist/src/manifestUpdater.d.ts +2 -1
- package/dist/src/specParser.browser.d.ts +1 -0
- package/dist/src/specParser.d.ts +1 -1
- package/dist/src/utils.d.ts +10 -9
- package/package.json +3 -3
package/dist/index.node.cjs.js
CHANGED
|
@@ -71,6 +71,21 @@ exports.ErrorType = void 0;
|
|
|
71
71
|
ErrorType["GenerateFailed"] = "generate-failed";
|
|
72
72
|
ErrorType["ValidateFailed"] = "validate-failed";
|
|
73
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";
|
|
74
89
|
ErrorType["Cancelled"] = "cancelled";
|
|
75
90
|
ErrorType["Unknown"] = "unknown";
|
|
76
91
|
})(exports.ErrorType || (exports.ErrorType = {}));
|
|
@@ -221,6 +236,7 @@ class Utils {
|
|
|
221
236
|
requiredNum: 0,
|
|
222
237
|
optionalNum: 0,
|
|
223
238
|
isValid: true,
|
|
239
|
+
reason: [],
|
|
224
240
|
};
|
|
225
241
|
if (!paramObject) {
|
|
226
242
|
return paramResult;
|
|
@@ -230,6 +246,7 @@ class Utils {
|
|
|
230
246
|
const schema = param.schema;
|
|
231
247
|
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
232
248
|
paramResult.isValid = false;
|
|
249
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
|
|
233
250
|
continue;
|
|
234
251
|
}
|
|
235
252
|
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
@@ -245,6 +262,7 @@ class Utils {
|
|
|
245
262
|
if (param.in === "header" || param.in === "cookie") {
|
|
246
263
|
if (isRequiredWithoutDefault) {
|
|
247
264
|
paramResult.isValid = false;
|
|
265
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
248
266
|
}
|
|
249
267
|
continue;
|
|
250
268
|
}
|
|
@@ -254,6 +272,7 @@ class Utils {
|
|
|
254
272
|
schema.type !== "integer") {
|
|
255
273
|
if (isRequiredWithoutDefault) {
|
|
256
274
|
paramResult.isValid = false;
|
|
275
|
+
paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
257
276
|
}
|
|
258
277
|
continue;
|
|
259
278
|
}
|
|
@@ -274,6 +293,7 @@ class Utils {
|
|
|
274
293
|
requiredNum: 0,
|
|
275
294
|
optionalNum: 0,
|
|
276
295
|
isValid: true,
|
|
296
|
+
reason: [],
|
|
277
297
|
};
|
|
278
298
|
if (Object.keys(schema).length === 0) {
|
|
279
299
|
return paramResult;
|
|
@@ -281,6 +301,7 @@ class Utils {
|
|
|
281
301
|
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
282
302
|
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
283
303
|
paramResult.isValid = false;
|
|
304
|
+
paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
|
|
284
305
|
return paramResult;
|
|
285
306
|
}
|
|
286
307
|
if (schema.type === "string" ||
|
|
@@ -305,11 +326,13 @@ class Utils {
|
|
|
305
326
|
paramResult.requiredNum += result.requiredNum;
|
|
306
327
|
paramResult.optionalNum += result.optionalNum;
|
|
307
328
|
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
329
|
+
paramResult.reason.push(...result.reason);
|
|
308
330
|
}
|
|
309
331
|
}
|
|
310
332
|
else {
|
|
311
333
|
if (isRequiredWithoutDefault && !isCopilot) {
|
|
312
334
|
paramResult.isValid = false;
|
|
335
|
+
paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
313
336
|
}
|
|
314
337
|
}
|
|
315
338
|
return paramResult;
|
|
@@ -333,103 +356,123 @@ class Utils {
|
|
|
333
356
|
*/
|
|
334
357
|
static isSupportedApi(method, path, spec, options) {
|
|
335
358
|
var _a;
|
|
336
|
-
const
|
|
359
|
+
const result = { isValid: true, reason: [] };
|
|
337
360
|
method = method.toLocaleLowerCase();
|
|
338
|
-
if (
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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);
|
|
386
423
|
}
|
|
387
|
-
|
|
388
|
-
if (
|
|
389
|
-
|
|
424
|
+
requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
|
|
425
|
+
if (!requestBodyParamResult.isValid && requestBodyParamResult.reason) {
|
|
426
|
+
result.reason.push(...requestBodyParamResult.reason);
|
|
390
427
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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);
|
|
396
441
|
}
|
|
397
|
-
return false;
|
|
398
442
|
}
|
|
399
|
-
else if (
|
|
400
|
-
|
|
401
|
-
paramResult.requiredNum +
|
|
402
|
-
paramResult.optionalNum ===
|
|
403
|
-
0) {
|
|
404
|
-
return false;
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
407
|
-
return true;
|
|
443
|
+
else if (totalParams === 0) {
|
|
444
|
+
result.reason.push(exports.ErrorType.NoParameter);
|
|
408
445
|
}
|
|
409
446
|
}
|
|
410
447
|
}
|
|
411
|
-
|
|
448
|
+
if (result.reason.length > 0) {
|
|
449
|
+
result.isValid = false;
|
|
450
|
+
}
|
|
451
|
+
return result;
|
|
412
452
|
}
|
|
413
453
|
static isSupportedAuth(authSchemeArray, options) {
|
|
414
454
|
if (authSchemeArray.length === 0) {
|
|
415
|
-
return true;
|
|
455
|
+
return { isValid: true, reason: [] };
|
|
416
456
|
}
|
|
417
457
|
if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
|
|
418
458
|
// Currently we don't support multiple auth in one operation
|
|
419
459
|
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
420
|
-
return
|
|
460
|
+
return {
|
|
461
|
+
isValid: false,
|
|
462
|
+
reason: [exports.ErrorType.MultipleAuthNotSupported],
|
|
463
|
+
};
|
|
421
464
|
}
|
|
422
465
|
for (const auths of authSchemeArray) {
|
|
423
466
|
if (auths.length === 1) {
|
|
424
467
|
if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
425
468
|
(options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
|
|
426
469
|
(options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
|
|
427
|
-
return true;
|
|
470
|
+
return { isValid: true, reason: [] };
|
|
428
471
|
}
|
|
429
472
|
}
|
|
430
473
|
}
|
|
431
474
|
}
|
|
432
|
-
return false;
|
|
475
|
+
return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
|
|
433
476
|
}
|
|
434
477
|
static isBearerTokenAuth(authScheme) {
|
|
435
478
|
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
@@ -472,11 +515,17 @@ class Utils {
|
|
|
472
515
|
static getResponseJson(operationObject, isTeamsAiProject = false) {
|
|
473
516
|
var _a, _b;
|
|
474
517
|
let json = {};
|
|
518
|
+
let multipleMediaType = false;
|
|
475
519
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
476
520
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
477
521
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
522
|
+
multipleMediaType = false;
|
|
478
523
|
json = responseObject.content["application/json"];
|
|
479
|
-
if (
|
|
524
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
525
|
+
multipleMediaType = true;
|
|
526
|
+
if (isTeamsAiProject) {
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
480
529
|
json = {};
|
|
481
530
|
}
|
|
482
531
|
else {
|
|
@@ -484,7 +533,7 @@ class Utils {
|
|
|
484
533
|
}
|
|
485
534
|
}
|
|
486
535
|
}
|
|
487
|
-
return json;
|
|
536
|
+
return { json, multipleMediaType };
|
|
488
537
|
}
|
|
489
538
|
static convertPathToCamelCase(path) {
|
|
490
539
|
const pathSegments = path.split(/[./{]/);
|
|
@@ -504,10 +553,10 @@ class Utils {
|
|
|
504
553
|
return undefined;
|
|
505
554
|
}
|
|
506
555
|
}
|
|
507
|
-
static
|
|
556
|
+
static resolveEnv(str) {
|
|
508
557
|
const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
|
|
509
|
-
let matches = placeHolderReg.exec(
|
|
510
|
-
let
|
|
558
|
+
let matches = placeHolderReg.exec(str);
|
|
559
|
+
let newStr = str;
|
|
511
560
|
while (matches != null) {
|
|
512
561
|
const envVar = matches[1];
|
|
513
562
|
const envVal = process.env[envVar];
|
|
@@ -515,17 +564,17 @@ class Utils {
|
|
|
515
564
|
throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
|
|
516
565
|
}
|
|
517
566
|
else {
|
|
518
|
-
|
|
567
|
+
newStr = newStr.replace(matches[0], envVal);
|
|
519
568
|
}
|
|
520
|
-
matches = placeHolderReg.exec(
|
|
569
|
+
matches = placeHolderReg.exec(str);
|
|
521
570
|
}
|
|
522
|
-
return
|
|
571
|
+
return newStr;
|
|
523
572
|
}
|
|
524
573
|
static checkServerUrl(servers) {
|
|
525
574
|
const errors = [];
|
|
526
575
|
let serverUrl;
|
|
527
576
|
try {
|
|
528
|
-
serverUrl = Utils.
|
|
577
|
+
serverUrl = Utils.resolveEnv(servers[0].url);
|
|
529
578
|
}
|
|
530
579
|
catch (err) {
|
|
531
580
|
errors.push({
|
|
@@ -556,6 +605,7 @@ class Utils {
|
|
|
556
605
|
return errors;
|
|
557
606
|
}
|
|
558
607
|
static validateServer(spec, options) {
|
|
608
|
+
var _a;
|
|
559
609
|
const errors = [];
|
|
560
610
|
let hasTopLevelServers = false;
|
|
561
611
|
let hasPathLevelServers = false;
|
|
@@ -576,7 +626,7 @@ class Utils {
|
|
|
576
626
|
}
|
|
577
627
|
for (const method in methods) {
|
|
578
628
|
const operationObject = methods[method];
|
|
579
|
-
if (
|
|
629
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
580
630
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
581
631
|
hasOperationLevelServers = true;
|
|
582
632
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -703,13 +753,7 @@ class Utils {
|
|
|
703
753
|
}
|
|
704
754
|
}
|
|
705
755
|
const operationId = operationItem.operationId;
|
|
706
|
-
const parameters = [];
|
|
707
|
-
if (requiredParams.length !== 0) {
|
|
708
|
-
parameters.push(...requiredParams);
|
|
709
|
-
}
|
|
710
|
-
else {
|
|
711
|
-
parameters.push(optionalParams[0]);
|
|
712
|
-
}
|
|
756
|
+
const parameters = [...requiredParams, ...optionalParams];
|
|
713
757
|
const command = {
|
|
714
758
|
context: ["compose"],
|
|
715
759
|
type: "query",
|
|
@@ -718,25 +762,23 @@ class Utils {
|
|
|
718
762
|
parameters: parameters,
|
|
719
763
|
description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
|
|
720
764
|
};
|
|
721
|
-
|
|
722
|
-
if (requiredParams.length === 0 && optionalParams.length > 1) {
|
|
723
|
-
warning = {
|
|
724
|
-
type: exports.WarningType.OperationOnlyContainsOptionalParam,
|
|
725
|
-
content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
|
|
726
|
-
data: operationId,
|
|
727
|
-
};
|
|
728
|
-
}
|
|
729
|
-
return [command, warning];
|
|
765
|
+
return command;
|
|
730
766
|
}
|
|
731
|
-
static
|
|
767
|
+
static listAPIs(spec, options) {
|
|
768
|
+
var _a;
|
|
732
769
|
const paths = spec.paths;
|
|
733
770
|
const result = {};
|
|
734
771
|
for (const path in paths) {
|
|
735
772
|
const methods = paths[path];
|
|
736
773
|
for (const method in methods) {
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
774
|
+
const operationObject = methods[method];
|
|
775
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
776
|
+
const validateResult = Utils.isSupportedApi(method, path, spec, options);
|
|
777
|
+
result[`${method.toUpperCase()} ${path}`] = {
|
|
778
|
+
operation: operationObject,
|
|
779
|
+
isValid: validateResult.isValid,
|
|
780
|
+
reason: validateResult.reason,
|
|
781
|
+
};
|
|
740
782
|
}
|
|
741
783
|
}
|
|
742
784
|
}
|
|
@@ -745,13 +787,13 @@ class Utils {
|
|
|
745
787
|
static validateSpec(spec, parser, isSwaggerFile, options) {
|
|
746
788
|
const errors = [];
|
|
747
789
|
const warnings = [];
|
|
790
|
+
const apiMap = Utils.listAPIs(spec, options);
|
|
748
791
|
if (isSwaggerFile) {
|
|
749
792
|
warnings.push({
|
|
750
793
|
type: exports.WarningType.ConvertSwaggerToOpenAPI,
|
|
751
794
|
content: ConstantString.ConvertSwaggerToOpenAPI,
|
|
752
795
|
});
|
|
753
796
|
}
|
|
754
|
-
// Server validation
|
|
755
797
|
const serverErrors = Utils.validateServer(spec, options);
|
|
756
798
|
errors.push(...serverErrors);
|
|
757
799
|
// Remote reference not supported
|
|
@@ -765,8 +807,8 @@ class Utils {
|
|
|
765
807
|
});
|
|
766
808
|
}
|
|
767
809
|
// No supported API
|
|
768
|
-
const
|
|
769
|
-
if (
|
|
810
|
+
const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
|
|
811
|
+
if (validAPIs.length === 0) {
|
|
770
812
|
errors.push({
|
|
771
813
|
type: exports.ErrorType.NoSupportedApi,
|
|
772
814
|
content: ConstantString.NoSupportedApi,
|
|
@@ -775,8 +817,8 @@ class Utils {
|
|
|
775
817
|
// OperationId missing
|
|
776
818
|
const apisMissingOperationId = [];
|
|
777
819
|
for (const key in apiMap) {
|
|
778
|
-
const
|
|
779
|
-
if (!
|
|
820
|
+
const { operation } = apiMap[key];
|
|
821
|
+
if (!operation.operationId) {
|
|
780
822
|
apisMissingOperationId.push(key);
|
|
781
823
|
}
|
|
782
824
|
}
|
|
@@ -835,25 +877,32 @@ class Utils {
|
|
|
835
877
|
// Copyright (c) Microsoft Corporation.
|
|
836
878
|
class SpecFilter {
|
|
837
879
|
static specFilter(filter, unResolveSpec, resolvedSpec, options) {
|
|
880
|
+
var _a;
|
|
838
881
|
try {
|
|
839
882
|
const newSpec = Object.assign({}, unResolveSpec);
|
|
840
883
|
const newPaths = {};
|
|
841
884
|
for (const filterItem of filter) {
|
|
842
885
|
const [method, path] = filterItem.split(" ");
|
|
843
886
|
const methodName = method.toLowerCase();
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
887
|
+
const pathObj = (_a = resolvedSpec.paths) === null || _a === void 0 ? void 0 : _a[path];
|
|
888
|
+
if (ConstantString.AllOperationMethods.includes(methodName) &&
|
|
889
|
+
pathObj &&
|
|
890
|
+
pathObj[methodName]) {
|
|
891
|
+
const validateResult = Utils.isSupportedApi(methodName, path, resolvedSpec, options);
|
|
892
|
+
if (!validateResult.isValid) {
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
if (!newPaths[path]) {
|
|
896
|
+
newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
|
|
897
|
+
for (const m of ConstantString.AllOperationMethods) {
|
|
898
|
+
delete newPaths[path][m];
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
|
|
902
|
+
// Add the operationId if missing
|
|
903
|
+
if (!newPaths[path][methodName].operationId) {
|
|
904
|
+
newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
|
|
851
905
|
}
|
|
852
|
-
}
|
|
853
|
-
newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
|
|
854
|
-
// Add the operationId if missing
|
|
855
|
-
if (!newPaths[path][methodName].operationId) {
|
|
856
|
-
newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
|
|
857
906
|
}
|
|
858
907
|
}
|
|
859
908
|
newSpec.paths = newPaths;
|
|
@@ -876,9 +925,10 @@ class ManifestUpdater {
|
|
|
876
925
|
pluginFile: apiPluginRelativePath,
|
|
877
926
|
},
|
|
878
927
|
];
|
|
928
|
+
const appName = this.removeEnvs(manifest.name.short);
|
|
879
929
|
ManifestUpdater.updateManifestDescription(manifest, spec);
|
|
880
930
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
881
|
-
const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
|
|
931
|
+
const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
|
|
882
932
|
return [manifest, apiPlugin];
|
|
883
933
|
});
|
|
884
934
|
}
|
|
@@ -903,7 +953,7 @@ class ManifestUpdater {
|
|
|
903
953
|
}
|
|
904
954
|
return parameter;
|
|
905
955
|
}
|
|
906
|
-
static generatePluginManifestSchema(spec, specRelativePath, options) {
|
|
956
|
+
static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
|
|
907
957
|
var _a, _b, _c;
|
|
908
958
|
const functions = [];
|
|
909
959
|
const functionNames = [];
|
|
@@ -968,7 +1018,7 @@ class ManifestUpdater {
|
|
|
968
1018
|
}
|
|
969
1019
|
const apiPlugin = {
|
|
970
1020
|
schema_version: "v2",
|
|
971
|
-
name_for_human:
|
|
1021
|
+
name_for_human: appName,
|
|
972
1022
|
description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
|
|
973
1023
|
functions: functions,
|
|
974
1024
|
runtimes: [
|
|
@@ -1055,16 +1105,26 @@ class ManifestUpdater {
|
|
|
1055
1105
|
if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
|
|
1056
1106
|
const operationItem = operations[method];
|
|
1057
1107
|
if (operationItem) {
|
|
1058
|
-
const
|
|
1108
|
+
const command = Utils.parseApiInfo(operationItem, options);
|
|
1109
|
+
if (command.parameters &&
|
|
1110
|
+
command.parameters.length >= 1 &&
|
|
1111
|
+
command.parameters.some((param) => param.isRequired)) {
|
|
1112
|
+
command.parameters = command.parameters.filter((param) => param.isRequired);
|
|
1113
|
+
}
|
|
1114
|
+
else if (command.parameters && command.parameters.length > 0) {
|
|
1115
|
+
command.parameters = [command.parameters[0]];
|
|
1116
|
+
warnings.push({
|
|
1117
|
+
type: exports.WarningType.OperationOnlyContainsOptionalParam,
|
|
1118
|
+
content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
|
|
1119
|
+
data: command.id,
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1059
1122
|
if (adaptiveCardFolder) {
|
|
1060
1123
|
const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
|
|
1061
1124
|
command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
|
|
1062
1125
|
? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
|
|
1063
1126
|
: "";
|
|
1064
1127
|
}
|
|
1065
|
-
if (warning) {
|
|
1066
|
-
warnings.push(warning);
|
|
1067
|
-
}
|
|
1068
1128
|
commands.push(command);
|
|
1069
1129
|
}
|
|
1070
1130
|
}
|
|
@@ -1079,13 +1139,22 @@ class ManifestUpdater {
|
|
|
1079
1139
|
const relativePath = path__default['default'].relative(path__default['default'].dirname(from), to);
|
|
1080
1140
|
return path__default['default'].normalize(relativePath).replace(/\\/g, "/");
|
|
1081
1141
|
}
|
|
1142
|
+
static removeEnvs(str) {
|
|
1143
|
+
const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
|
|
1144
|
+
const matches = placeHolderReg.exec(str);
|
|
1145
|
+
let newStr = str;
|
|
1146
|
+
if (matches != null) {
|
|
1147
|
+
newStr = newStr.replace(matches[0], "");
|
|
1148
|
+
}
|
|
1149
|
+
return newStr;
|
|
1150
|
+
}
|
|
1082
1151
|
}
|
|
1083
1152
|
|
|
1084
1153
|
// Copyright (c) Microsoft Corporation.
|
|
1085
1154
|
class AdaptiveCardGenerator {
|
|
1086
1155
|
static generateAdaptiveCard(operationItem) {
|
|
1087
1156
|
try {
|
|
1088
|
-
const json = Utils.getResponseJson(operationItem);
|
|
1157
|
+
const { json } = Utils.getResponseJson(operationItem);
|
|
1089
1158
|
let cardBody = [];
|
|
1090
1159
|
let schema = json.schema;
|
|
1091
1160
|
let jsonPath = "$";
|
|
@@ -1423,20 +1492,22 @@ class SpecParser {
|
|
|
1423
1492
|
try {
|
|
1424
1493
|
yield this.loadSpec();
|
|
1425
1494
|
const spec = this.spec;
|
|
1426
|
-
const apiMap = this.
|
|
1495
|
+
const apiMap = this.getAPIs(spec);
|
|
1427
1496
|
const result = {
|
|
1428
|
-
|
|
1497
|
+
APIs: [],
|
|
1429
1498
|
allAPICount: 0,
|
|
1430
1499
|
validAPICount: 0,
|
|
1431
1500
|
};
|
|
1432
1501
|
for (const apiKey in apiMap) {
|
|
1502
|
+
const { operation, isValid, reason } = apiMap[apiKey];
|
|
1503
|
+
const [method, path] = apiKey.split(" ");
|
|
1433
1504
|
const apiResult = {
|
|
1434
1505
|
api: "",
|
|
1435
1506
|
server: "",
|
|
1436
1507
|
operationId: "",
|
|
1508
|
+
isValid: isValid,
|
|
1509
|
+
reason: reason,
|
|
1437
1510
|
};
|
|
1438
|
-
const [method, path] = apiKey.split(" ");
|
|
1439
|
-
const operation = apiMap[apiKey];
|
|
1440
1511
|
const rootServer = spec.servers && spec.servers[0];
|
|
1441
1512
|
const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
|
|
1442
1513
|
const operationServer = operation.servers && operation.servers[0];
|
|
@@ -1444,7 +1515,7 @@ class SpecParser {
|
|
|
1444
1515
|
if (!serverUrl) {
|
|
1445
1516
|
throw new SpecParserError(ConstantString.NoServerInformation, exports.ErrorType.NoServerInformation);
|
|
1446
1517
|
}
|
|
1447
|
-
apiResult.server = Utils.
|
|
1518
|
+
apiResult.server = Utils.resolveEnv(serverUrl.url);
|
|
1448
1519
|
let operationId = operation.operationId;
|
|
1449
1520
|
if (!operationId) {
|
|
1450
1521
|
operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
|
|
@@ -1458,10 +1529,10 @@ class SpecParser {
|
|
|
1458
1529
|
}
|
|
1459
1530
|
}
|
|
1460
1531
|
apiResult.api = apiKey;
|
|
1461
|
-
result.
|
|
1532
|
+
result.APIs.push(apiResult);
|
|
1462
1533
|
}
|
|
1463
|
-
result.allAPICount =
|
|
1464
|
-
result.validAPICount = result.
|
|
1534
|
+
result.allAPICount = result.APIs.length;
|
|
1535
|
+
result.validAPICount = result.APIs.filter((api) => api.isValid).length;
|
|
1465
1536
|
return result;
|
|
1466
1537
|
}
|
|
1467
1538
|
catch (err) {
|
|
@@ -1559,15 +1630,18 @@ class SpecParser {
|
|
|
1559
1630
|
const newSpecs = yield this.getFilteredSpecs(filter, signal);
|
|
1560
1631
|
const newUnResolvedSpec = newSpecs[0];
|
|
1561
1632
|
const newSpec = newSpecs[1];
|
|
1562
|
-
const authSet = new Set();
|
|
1563
1633
|
let hasMultipleAuth = false;
|
|
1634
|
+
let authInfo = undefined;
|
|
1564
1635
|
for (const url in newSpec.paths) {
|
|
1565
1636
|
for (const method in newSpec.paths[url]) {
|
|
1566
1637
|
const operation = newSpec.paths[url][method];
|
|
1567
1638
|
const authArray = Utils.getAuthArray(operation.security, newSpec);
|
|
1568
1639
|
if (authArray && authArray.length > 0) {
|
|
1569
|
-
|
|
1570
|
-
if (
|
|
1640
|
+
const currentAuth = authArray[0][0];
|
|
1641
|
+
if (!authInfo) {
|
|
1642
|
+
authInfo = authArray[0][0];
|
|
1643
|
+
}
|
|
1644
|
+
else if (authInfo.name !== currentAuth.name) {
|
|
1571
1645
|
hasMultipleAuth = true;
|
|
1572
1646
|
break;
|
|
1573
1647
|
}
|
|
@@ -1614,7 +1688,6 @@ class SpecParser {
|
|
|
1614
1688
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1615
1689
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1616
1690
|
}
|
|
1617
|
-
const authInfo = Array.from(authSet)[0];
|
|
1618
1691
|
const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
|
|
1619
1692
|
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
|
|
1620
1693
|
result.warnings.push(...warnings);
|
|
@@ -1643,11 +1716,11 @@ class SpecParser {
|
|
|
1643
1716
|
}
|
|
1644
1717
|
});
|
|
1645
1718
|
}
|
|
1646
|
-
|
|
1719
|
+
getAPIs(spec) {
|
|
1647
1720
|
if (this.apiMap !== undefined) {
|
|
1648
1721
|
return this.apiMap;
|
|
1649
1722
|
}
|
|
1650
|
-
const result = Utils.
|
|
1723
|
+
const result = Utils.listAPIs(spec, this.options);
|
|
1651
1724
|
this.apiMap = result;
|
|
1652
1725
|
return result;
|
|
1653
1726
|
}
|