@microsoft/m365-spec-parser 0.1.1-alpha.a372ccf67.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.
@@ -62,6 +62,7 @@ exports.ErrorType = void 0;
62
62
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
63
63
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
64
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";
@@ -70,6 +71,21 @@ exports.ErrorType = void 0;
70
71
  ErrorType["GenerateFailed"] = "generate-failed";
71
72
  ErrorType["ValidateFailed"] = "validate-failed";
72
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";
73
89
  ErrorType["Cancelled"] = "cancelled";
74
90
  ErrorType["Unknown"] = "unknown";
75
91
  })(exports.ErrorType || (exports.ErrorType = {}));
@@ -117,6 +133,7 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
117
133
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
118
134
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
119
135
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
136
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
120
137
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
121
138
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
122
139
  ConstantString.WrappedCardVersion = "devPreview";
@@ -219,6 +236,7 @@ class Utils {
219
236
  requiredNum: 0,
220
237
  optionalNum: 0,
221
238
  isValid: true,
239
+ reason: [],
222
240
  };
223
241
  if (!paramObject) {
224
242
  return paramResult;
@@ -228,6 +246,7 @@ class Utils {
228
246
  const schema = param.schema;
229
247
  if (isCopilot && this.hasNestedObjectInSchema(schema)) {
230
248
  paramResult.isValid = false;
249
+ paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
231
250
  continue;
232
251
  }
233
252
  const isRequiredWithoutDefault = param.required && schema.default === undefined;
@@ -243,6 +262,7 @@ class Utils {
243
262
  if (param.in === "header" || param.in === "cookie") {
244
263
  if (isRequiredWithoutDefault) {
245
264
  paramResult.isValid = false;
265
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
246
266
  }
247
267
  continue;
248
268
  }
@@ -252,6 +272,7 @@ class Utils {
252
272
  schema.type !== "integer") {
253
273
  if (isRequiredWithoutDefault) {
254
274
  paramResult.isValid = false;
275
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
255
276
  }
256
277
  continue;
257
278
  }
@@ -272,6 +293,7 @@ class Utils {
272
293
  requiredNum: 0,
273
294
  optionalNum: 0,
274
295
  isValid: true,
296
+ reason: [],
275
297
  };
276
298
  if (Object.keys(schema).length === 0) {
277
299
  return paramResult;
@@ -279,6 +301,7 @@ class Utils {
279
301
  const isRequiredWithoutDefault = isRequired && schema.default === undefined;
280
302
  if (isCopilot && this.hasNestedObjectInSchema(schema)) {
281
303
  paramResult.isValid = false;
304
+ paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
282
305
  return paramResult;
283
306
  }
284
307
  if (schema.type === "string" ||
@@ -303,11 +326,13 @@ class Utils {
303
326
  paramResult.requiredNum += result.requiredNum;
304
327
  paramResult.optionalNum += result.optionalNum;
305
328
  paramResult.isValid = paramResult.isValid && result.isValid;
329
+ paramResult.reason.push(...result.reason);
306
330
  }
307
331
  }
308
332
  else {
309
333
  if (isRequiredWithoutDefault && !isCopilot) {
310
334
  paramResult.isValid = false;
335
+ paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
311
336
  }
312
337
  }
313
338
  return paramResult;
@@ -331,120 +356,132 @@ class Utils {
331
356
  */
332
357
  static isSupportedApi(method, path, spec, options) {
333
358
  var _a;
334
- const pathObj = spec.paths[path];
359
+ const result = { isValid: true, reason: [] };
335
360
  method = method.toLocaleLowerCase();
336
- if (pathObj) {
337
- if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
338
- const securities = pathObj[method].security;
339
- const isTeamsAi = options.projectType === exports.ProjectType.TeamsAi;
340
- const isCopilot = options.projectType === exports.ProjectType.Copilot;
341
- // Teams AI project doesn't care about auth, it will use authProvider for user to implement
342
- if (!isTeamsAi) {
343
- const authArray = Utils.getAuthArray(securities, spec);
344
- if (!Utils.isSupportedAuth(authArray, options)) {
345
- return false;
346
- }
347
- }
348
- const operationObject = pathObj[method];
349
- if (!options.allowMissingId && !operationObject.operationId) {
350
- return false;
351
- }
352
- const paramObject = operationObject.parameters;
353
- const requestBody = operationObject.requestBody;
354
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
355
- if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
356
- return false;
357
- }
358
- const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
359
- if (Object.keys(responseJson).length === 0) {
360
- return false;
361
- }
362
- // Teams AI project doesn't care about request parameters/body
363
- if (isTeamsAi) {
364
- return true;
365
- }
366
- let requestBodyParamResult = {
367
- requiredNum: 0,
368
- optionalNum: 0,
369
- isValid: true,
370
- };
371
- if (requestJsonBody) {
372
- const requestBodySchema = requestJsonBody.schema;
373
- if (isCopilot && requestBodySchema.type !== "object") {
374
- return false;
375
- }
376
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
377
- }
378
- if (!requestBodyParamResult.isValid) {
379
- return false;
380
- }
381
- const paramResult = Utils.checkParameters(paramObject, isCopilot);
382
- if (!paramResult.isValid) {
383
- return false;
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);
384
423
  }
385
- // Copilot support arbitrary parameters
386
- if (isCopilot) {
387
- return true;
424
+ requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
425
+ if (!requestBodyParamResult.isValid && requestBodyParamResult.reason) {
426
+ result.reason.push(...requestBodyParamResult.reason);
388
427
  }
389
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
390
- if (options.allowMultipleParameters &&
391
- requestBodyParamResult.requiredNum + paramResult.requiredNum <=
392
- ConstantString.SMERequiredParamsMaxNum) {
393
- return true;
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);
394
441
  }
395
- return false;
396
- }
397
- else if (requestBodyParamResult.requiredNum +
398
- requestBodyParamResult.optionalNum +
399
- paramResult.requiredNum +
400
- paramResult.optionalNum ===
401
- 0) {
402
- return false;
403
442
  }
404
- else {
405
- return true;
443
+ else if (totalParams === 0) {
444
+ result.reason.push(exports.ErrorType.NoParameter);
406
445
  }
407
446
  }
408
447
  }
409
- return false;
448
+ if (result.reason.length > 0) {
449
+ result.isValid = false;
450
+ }
451
+ return result;
410
452
  }
411
- static isSupportedAuth(authSchemaArray, options) {
412
- if (authSchemaArray.length === 0) {
413
- return true;
453
+ static isSupportedAuth(authSchemeArray, options) {
454
+ if (authSchemeArray.length === 0) {
455
+ return { isValid: true, reason: [] };
414
456
  }
415
- if (options.allowAPIKeyAuth || options.allowOauth2) {
457
+ if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
416
458
  // Currently we don't support multiple auth in one operation
417
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
418
- return false;
459
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
460
+ return {
461
+ isValid: false,
462
+ reason: [exports.ErrorType.MultipleAuthNotSupported],
463
+ };
419
464
  }
420
- for (const auths of authSchemaArray) {
465
+ for (const auths of authSchemeArray) {
421
466
  if (auths.length === 1) {
422
- if (!options.allowOauth2 &&
423
- options.allowAPIKeyAuth &&
424
- Utils.isAPIKeyAuth(auths[0].authSchema)) {
425
- return true;
426
- }
427
- else if (!options.allowAPIKeyAuth &&
428
- options.allowOauth2 &&
429
- Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema)) {
430
- return true;
431
- }
432
- else if (options.allowAPIKeyAuth &&
433
- options.allowOauth2 &&
434
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
435
- Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema))) {
436
- return true;
467
+ if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
468
+ (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
469
+ (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
470
+ return { isValid: true, reason: [] };
437
471
  }
438
472
  }
439
473
  }
440
474
  }
441
- return false;
475
+ return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
476
+ }
477
+ static isBearerTokenAuth(authScheme) {
478
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
442
479
  }
443
- static isAPIKeyAuth(authSchema) {
444
- return authSchema.type === "apiKey";
480
+ static isAPIKeyAuth(authScheme) {
481
+ return authScheme.type === "apiKey";
445
482
  }
446
- static isOAuthWithAuthCodeFlow(authSchema) {
447
- if (authSchema.type === "oauth2" && authSchema.flows && authSchema.flows.authorizationCode) {
483
+ static isOAuthWithAuthCodeFlow(authScheme) {
484
+ if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
448
485
  return true;
449
486
  }
450
487
  return false;
@@ -460,7 +497,7 @@ class Utils {
460
497
  for (const name in security) {
461
498
  const auth = securitySchemas[name];
462
499
  authArray.push({
463
- authSchema: auth,
500
+ authScheme: auth,
464
501
  name: name,
465
502
  });
466
503
  }
@@ -478,11 +515,17 @@ class Utils {
478
515
  static getResponseJson(operationObject, isTeamsAiProject = false) {
479
516
  var _a, _b;
480
517
  let json = {};
518
+ let multipleMediaType = false;
481
519
  for (const code of ConstantString.ResponseCodeFor20X) {
482
520
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
483
521
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
522
+ multipleMediaType = false;
484
523
  json = responseObject.content["application/json"];
485
- if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
524
+ if (Utils.containMultipleMediaTypes(responseObject)) {
525
+ multipleMediaType = true;
526
+ if (isTeamsAiProject) {
527
+ break;
528
+ }
486
529
  json = {};
487
530
  }
488
531
  else {
@@ -490,7 +533,7 @@ class Utils {
490
533
  }
491
534
  }
492
535
  }
493
- return json;
536
+ return { json, multipleMediaType };
494
537
  }
495
538
  static convertPathToCamelCase(path) {
496
539
  const pathSegments = path.split(/[./{]/);
@@ -510,10 +553,10 @@ class Utils {
510
553
  return undefined;
511
554
  }
512
555
  }
513
- static resolveServerUrl(url) {
556
+ static resolveEnv(str) {
514
557
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
515
- let matches = placeHolderReg.exec(url);
516
- let newUrl = url;
558
+ let matches = placeHolderReg.exec(str);
559
+ let newStr = str;
517
560
  while (matches != null) {
518
561
  const envVar = matches[1];
519
562
  const envVal = process.env[envVar];
@@ -521,17 +564,17 @@ class Utils {
521
564
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
522
565
  }
523
566
  else {
524
- newUrl = newUrl.replace(matches[0], envVal);
567
+ newStr = newStr.replace(matches[0], envVal);
525
568
  }
526
- matches = placeHolderReg.exec(url);
569
+ matches = placeHolderReg.exec(str);
527
570
  }
528
- return newUrl;
571
+ return newStr;
529
572
  }
530
573
  static checkServerUrl(servers) {
531
574
  const errors = [];
532
575
  let serverUrl;
533
576
  try {
534
- serverUrl = Utils.resolveServerUrl(servers[0].url);
577
+ serverUrl = Utils.resolveEnv(servers[0].url);
535
578
  }
536
579
  catch (err) {
537
580
  errors.push({
@@ -562,6 +605,7 @@ class Utils {
562
605
  return errors;
563
606
  }
564
607
  static validateServer(spec, options) {
608
+ var _a;
565
609
  const errors = [];
566
610
  let hasTopLevelServers = false;
567
611
  let hasPathLevelServers = false;
@@ -582,7 +626,7 @@ class Utils {
582
626
  }
583
627
  for (const method in methods) {
584
628
  const operationObject = methods[method];
585
- if (Utils.isSupportedApi(method, path, spec, options)) {
629
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
586
630
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
587
631
  hasOperationLevelServers = true;
588
632
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -625,6 +669,7 @@ class Utils {
625
669
  Utils.updateParameterWithInputType(schema, parameter);
626
670
  }
627
671
  if (isRequired && schema.default === undefined) {
672
+ parameter.isRequired = true;
628
673
  requiredParams.push(parameter);
629
674
  }
630
675
  else {
@@ -688,6 +733,7 @@ class Utils {
688
733
  }
689
734
  if (param.in !== "header" && param.in !== "cookie") {
690
735
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
736
+ parameter.isRequired = true;
691
737
  requiredParams.push(parameter);
692
738
  }
693
739
  else {
@@ -707,13 +753,7 @@ class Utils {
707
753
  }
708
754
  }
709
755
  const operationId = operationItem.operationId;
710
- const parameters = [];
711
- if (requiredParams.length !== 0) {
712
- parameters.push(...requiredParams);
713
- }
714
- else {
715
- parameters.push(optionalParams[0]);
716
- }
756
+ const parameters = [...requiredParams, ...optionalParams];
717
757
  const command = {
718
758
  context: ["compose"],
719
759
  type: "query",
@@ -722,25 +762,23 @@ class Utils {
722
762
  parameters: parameters,
723
763
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
724
764
  };
725
- let warning = undefined;
726
- if (requiredParams.length === 0 && optionalParams.length > 1) {
727
- warning = {
728
- type: exports.WarningType.OperationOnlyContainsOptionalParam,
729
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
730
- data: operationId,
731
- };
732
- }
733
- return [command, warning];
765
+ return command;
734
766
  }
735
- static listSupportedAPIs(spec, options) {
767
+ static listAPIs(spec, options) {
768
+ var _a;
736
769
  const paths = spec.paths;
737
770
  const result = {};
738
771
  for (const path in paths) {
739
772
  const methods = paths[path];
740
773
  for (const method in methods) {
741
- if (Utils.isSupportedApi(method, path, spec, options)) {
742
- const operationObject = methods[method];
743
- result[`${method.toUpperCase()} ${path}`] = operationObject;
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
+ };
744
782
  }
745
783
  }
746
784
  }
@@ -749,13 +787,13 @@ class Utils {
749
787
  static validateSpec(spec, parser, isSwaggerFile, options) {
750
788
  const errors = [];
751
789
  const warnings = [];
790
+ const apiMap = Utils.listAPIs(spec, options);
752
791
  if (isSwaggerFile) {
753
792
  warnings.push({
754
793
  type: exports.WarningType.ConvertSwaggerToOpenAPI,
755
794
  content: ConstantString.ConvertSwaggerToOpenAPI,
756
795
  });
757
796
  }
758
- // Server validation
759
797
  const serverErrors = Utils.validateServer(spec, options);
760
798
  errors.push(...serverErrors);
761
799
  // Remote reference not supported
@@ -769,8 +807,8 @@ class Utils {
769
807
  });
770
808
  }
771
809
  // No supported API
772
- const apiMap = Utils.listSupportedAPIs(spec, options);
773
- if (Object.keys(apiMap).length === 0) {
810
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
811
+ if (validAPIs.length === 0) {
774
812
  errors.push({
775
813
  type: exports.ErrorType.NoSupportedApi,
776
814
  content: ConstantString.NoSupportedApi,
@@ -779,8 +817,8 @@ class Utils {
779
817
  // OperationId missing
780
818
  const apisMissingOperationId = [];
781
819
  for (const key in apiMap) {
782
- const pathObjectItem = apiMap[key];
783
- if (!pathObjectItem.operationId) {
820
+ const { operation } = apiMap[key];
821
+ if (!operation.operationId) {
784
822
  apisMissingOperationId.push(key);
785
823
  }
786
824
  }
@@ -821,30 +859,50 @@ class Utils {
821
859
  }
822
860
  return safeRegistrationIdEnvName;
823
861
  }
862
+ static getAllAPICount(spec) {
863
+ let count = 0;
864
+ const paths = spec.paths;
865
+ for (const path in paths) {
866
+ const methods = paths[path];
867
+ for (const method in methods) {
868
+ if (ConstantString.AllOperationMethods.includes(method)) {
869
+ count++;
870
+ }
871
+ }
872
+ }
873
+ return count;
874
+ }
824
875
  }
825
876
 
826
877
  // Copyright (c) Microsoft Corporation.
827
878
  class SpecFilter {
828
879
  static specFilter(filter, unResolveSpec, resolvedSpec, options) {
880
+ var _a;
829
881
  try {
830
882
  const newSpec = Object.assign({}, unResolveSpec);
831
883
  const newPaths = {};
832
884
  for (const filterItem of filter) {
833
885
  const [method, path] = filterItem.split(" ");
834
886
  const methodName = method.toLowerCase();
835
- if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
836
- continue;
837
- }
838
- if (!newPaths[path]) {
839
- newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
840
- for (const m of ConstantString.AllOperationMethods) {
841
- delete newPaths[path][m];
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)}`;
842
905
  }
843
- }
844
- newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
845
- // Add the operationId if missing
846
- if (!newPaths[path][methodName].operationId) {
847
- newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
848
906
  }
849
907
  }
850
908
  newSpec.paths = newPaths;
@@ -867,9 +925,10 @@ class ManifestUpdater {
867
925
  pluginFile: apiPluginRelativePath,
868
926
  },
869
927
  ];
928
+ const appName = this.removeEnvs(manifest.name.short);
870
929
  ManifestUpdater.updateManifestDescription(manifest, spec);
871
930
  const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
872
- const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
931
+ const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
873
932
  return [manifest, apiPlugin];
874
933
  });
875
934
  }
@@ -894,7 +953,7 @@ class ManifestUpdater {
894
953
  }
895
954
  return parameter;
896
955
  }
897
- static generatePluginManifestSchema(spec, specRelativePath, options) {
956
+ static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
898
957
  var _a, _b, _c;
899
958
  const functions = [];
900
959
  const functionNames = [];
@@ -959,7 +1018,7 @@ class ManifestUpdater {
959
1018
  }
960
1019
  const apiPlugin = {
961
1020
  schema_version: "v2",
962
- name_for_human: spec.info.title,
1021
+ name_for_human: appName,
963
1022
  description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
964
1023
  functions: functions,
965
1024
  runtimes: [
@@ -994,9 +1053,8 @@ class ManifestUpdater {
994
1053
  commands: commands,
995
1054
  };
996
1055
  if (authInfo) {
997
- let auth = authInfo.authSchema;
998
- if (Utils.isAPIKeyAuth(auth)) {
999
- auth = auth;
1056
+ const auth = authInfo.authScheme;
1057
+ if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1000
1058
  const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
1001
1059
  composeExtension.authorization = {
1002
1060
  authType: "apiSecretServiceAuth",
@@ -1047,16 +1105,26 @@ class ManifestUpdater {
1047
1105
  if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
1048
1106
  const operationItem = operations[method];
1049
1107
  if (operationItem) {
1050
- const [command, warning] = Utils.parseApiInfo(operationItem, options);
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
+ }
1051
1122
  if (adaptiveCardFolder) {
1052
1123
  const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
1053
1124
  command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
1054
1125
  ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
1055
1126
  : "";
1056
1127
  }
1057
- if (warning) {
1058
- warnings.push(warning);
1059
- }
1060
1128
  commands.push(command);
1061
1129
  }
1062
1130
  }
@@ -1071,13 +1139,22 @@ class ManifestUpdater {
1071
1139
  const relativePath = path__default['default'].relative(path__default['default'].dirname(from), to);
1072
1140
  return path__default['default'].normalize(relativePath).replace(/\\/g, "/");
1073
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
+ }
1074
1151
  }
1075
1152
 
1076
1153
  // Copyright (c) Microsoft Corporation.
1077
1154
  class AdaptiveCardGenerator {
1078
1155
  static generateAdaptiveCard(operationItem) {
1079
1156
  try {
1080
- const json = Utils.getResponseJson(operationItem);
1157
+ const { json } = Utils.getResponseJson(operationItem);
1081
1158
  let cardBody = [];
1082
1159
  let schema = json.schema;
1083
1160
  let jsonPath = "$";
@@ -1337,6 +1414,7 @@ class SpecParser {
1337
1414
  allowMissingId: true,
1338
1415
  allowSwagger: true,
1339
1416
  allowAPIKeyAuth: false,
1417
+ allowBearerTokenAuth: false,
1340
1418
  allowMultipleParameters: false,
1341
1419
  allowOauth2: false,
1342
1420
  allowMethods: ["get", "post"],
@@ -1374,6 +1452,22 @@ class SpecParser {
1374
1452
  ],
1375
1453
  };
1376
1454
  }
1455
+ if (this.options.projectType === exports.ProjectType.SME ||
1456
+ this.options.projectType === exports.ProjectType.Copilot) {
1457
+ if (this.spec.openapi >= "3.1.0") {
1458
+ return {
1459
+ status: exports.ValidationStatus.Error,
1460
+ warnings: [],
1461
+ errors: [
1462
+ {
1463
+ type: exports.ErrorType.SpecVersionNotSupported,
1464
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
1465
+ data: this.spec.openapi,
1466
+ },
1467
+ ],
1468
+ };
1469
+ }
1470
+ }
1377
1471
  return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1378
1472
  }
1379
1473
  catch (err) {
@@ -1398,16 +1492,22 @@ class SpecParser {
1398
1492
  try {
1399
1493
  yield this.loadSpec();
1400
1494
  const spec = this.spec;
1401
- const apiMap = this.getAllSupportedAPIs(spec);
1402
- const result = [];
1495
+ const apiMap = this.getAPIs(spec);
1496
+ const result = {
1497
+ APIs: [],
1498
+ allAPICount: 0,
1499
+ validAPICount: 0,
1500
+ };
1403
1501
  for (const apiKey in apiMap) {
1502
+ const { operation, isValid, reason } = apiMap[apiKey];
1503
+ const [method, path] = apiKey.split(" ");
1404
1504
  const apiResult = {
1405
1505
  api: "",
1406
1506
  server: "",
1407
1507
  operationId: "",
1508
+ isValid: isValid,
1509
+ reason: reason,
1408
1510
  };
1409
- const [method, path] = apiKey.split(" ");
1410
- const operation = apiMap[apiKey];
1411
1511
  const rootServer = spec.servers && spec.servers[0];
1412
1512
  const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
1413
1513
  const operationServer = operation.servers && operation.servers[0];
@@ -1415,7 +1515,7 @@ class SpecParser {
1415
1515
  if (!serverUrl) {
1416
1516
  throw new SpecParserError(ConstantString.NoServerInformation, exports.ErrorType.NoServerInformation);
1417
1517
  }
1418
- apiResult.server = Utils.resolveServerUrl(serverUrl.url);
1518
+ apiResult.server = Utils.resolveEnv(serverUrl.url);
1419
1519
  let operationId = operation.operationId;
1420
1520
  if (!operationId) {
1421
1521
  operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
@@ -1424,13 +1524,15 @@ class SpecParser {
1424
1524
  const authArray = Utils.getAuthArray(operation.security, spec);
1425
1525
  for (const auths of authArray) {
1426
1526
  if (auths.length === 1) {
1427
- apiResult.auth = auths[0].authSchema;
1527
+ apiResult.auth = auths[0];
1428
1528
  break;
1429
1529
  }
1430
1530
  }
1431
1531
  apiResult.api = apiKey;
1432
- result.push(apiResult);
1532
+ result.APIs.push(apiResult);
1433
1533
  }
1534
+ result.allAPICount = result.APIs.length;
1535
+ result.validAPICount = result.APIs.filter((api) => api.isValid).length;
1434
1536
  return result;
1435
1537
  }
1436
1538
  catch (err) {
@@ -1528,15 +1630,18 @@ class SpecParser {
1528
1630
  const newSpecs = yield this.getFilteredSpecs(filter, signal);
1529
1631
  const newUnResolvedSpec = newSpecs[0];
1530
1632
  const newSpec = newSpecs[1];
1531
- const authSet = new Set();
1532
1633
  let hasMultipleAuth = false;
1634
+ let authInfo = undefined;
1533
1635
  for (const url in newSpec.paths) {
1534
1636
  for (const method in newSpec.paths[url]) {
1535
1637
  const operation = newSpec.paths[url][method];
1536
1638
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1537
1639
  if (authArray && authArray.length > 0) {
1538
- authSet.add(authArray[0][0]);
1539
- if (authSet.size > 1) {
1640
+ const currentAuth = authArray[0][0];
1641
+ if (!authInfo) {
1642
+ authInfo = authArray[0][0];
1643
+ }
1644
+ else if (authInfo.name !== currentAuth.name) {
1540
1645
  hasMultipleAuth = true;
1541
1646
  break;
1542
1647
  }
@@ -1583,7 +1688,6 @@ class SpecParser {
1583
1688
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1584
1689
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1585
1690
  }
1586
- const authInfo = Array.from(authSet)[0];
1587
1691
  const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1588
1692
  yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1589
1693
  result.warnings.push(...warnings);
@@ -1612,11 +1716,11 @@ class SpecParser {
1612
1716
  }
1613
1717
  });
1614
1718
  }
1615
- getAllSupportedAPIs(spec) {
1719
+ getAPIs(spec) {
1616
1720
  if (this.apiMap !== undefined) {
1617
1721
  return this.apiMap;
1618
1722
  }
1619
- const result = Utils.listSupportedAPIs(spec, this.options);
1723
+ const result = Utils.listAPIs(spec, this.options);
1620
1724
  this.apiMap = result;
1621
1725
  return result;
1622
1726
  }