@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.
@@ -20,6 +20,7 @@ var ErrorType;
20
20
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
21
21
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
22
22
  ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
23
+ ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
23
24
  ErrorType["ListFailed"] = "list-failed";
24
25
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
25
26
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -28,6 +29,21 @@ var ErrorType;
28
29
  ErrorType["GenerateFailed"] = "generate-failed";
29
30
  ErrorType["ValidateFailed"] = "validate-failed";
30
31
  ErrorType["GetSpecFailed"] = "get-spec-failed";
32
+ ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
33
+ ErrorType["MissingOperationId"] = "missing-operation-id";
34
+ ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
35
+ ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
36
+ ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
37
+ ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
38
+ ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
39
+ ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
40
+ ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
41
+ ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
42
+ ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
43
+ ErrorType["NoParameter"] = "no-parameter";
44
+ ErrorType["NoAPIInfo"] = "no-api-info";
45
+ ErrorType["MethodNotAllowed"] = "method-not-allowed";
46
+ ErrorType["UrlPathNotExist"] = "url-path-not-exist";
31
47
  ErrorType["Cancelled"] = "cancelled";
32
48
  ErrorType["Unknown"] = "unknown";
33
49
  })(ErrorType || (ErrorType = {}));
@@ -75,6 +91,7 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
75
91
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
76
92
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
77
93
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
94
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
78
95
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
79
96
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
80
97
  ConstantString.WrappedCardVersion = "devPreview";
@@ -177,6 +194,7 @@ class Utils {
177
194
  requiredNum: 0,
178
195
  optionalNum: 0,
179
196
  isValid: true,
197
+ reason: [],
180
198
  };
181
199
  if (!paramObject) {
182
200
  return paramResult;
@@ -186,6 +204,7 @@ class Utils {
186
204
  const schema = param.schema;
187
205
  if (isCopilot && this.hasNestedObjectInSchema(schema)) {
188
206
  paramResult.isValid = false;
207
+ paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
189
208
  continue;
190
209
  }
191
210
  const isRequiredWithoutDefault = param.required && schema.default === undefined;
@@ -201,6 +220,7 @@ class Utils {
201
220
  if (param.in === "header" || param.in === "cookie") {
202
221
  if (isRequiredWithoutDefault) {
203
222
  paramResult.isValid = false;
223
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
204
224
  }
205
225
  continue;
206
226
  }
@@ -210,6 +230,7 @@ class Utils {
210
230
  schema.type !== "integer") {
211
231
  if (isRequiredWithoutDefault) {
212
232
  paramResult.isValid = false;
233
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
213
234
  }
214
235
  continue;
215
236
  }
@@ -230,6 +251,7 @@ class Utils {
230
251
  requiredNum: 0,
231
252
  optionalNum: 0,
232
253
  isValid: true,
254
+ reason: [],
233
255
  };
234
256
  if (Object.keys(schema).length === 0) {
235
257
  return paramResult;
@@ -237,6 +259,7 @@ class Utils {
237
259
  const isRequiredWithoutDefault = isRequired && schema.default === undefined;
238
260
  if (isCopilot && this.hasNestedObjectInSchema(schema)) {
239
261
  paramResult.isValid = false;
262
+ paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
240
263
  return paramResult;
241
264
  }
242
265
  if (schema.type === "string" ||
@@ -261,11 +284,13 @@ class Utils {
261
284
  paramResult.requiredNum += result.requiredNum;
262
285
  paramResult.optionalNum += result.optionalNum;
263
286
  paramResult.isValid = paramResult.isValid && result.isValid;
287
+ paramResult.reason.push(...result.reason);
264
288
  }
265
289
  }
266
290
  else {
267
291
  if (isRequiredWithoutDefault && !isCopilot) {
268
292
  paramResult.isValid = false;
293
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
269
294
  }
270
295
  }
271
296
  return paramResult;
@@ -289,120 +314,132 @@ class Utils {
289
314
  */
290
315
  static isSupportedApi(method, path, spec, options) {
291
316
  var _a;
292
- const pathObj = spec.paths[path];
317
+ const result = { isValid: true, reason: [] };
293
318
  method = method.toLocaleLowerCase();
294
- if (pathObj) {
295
- if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
296
- const securities = pathObj[method].security;
297
- const isTeamsAi = options.projectType === ProjectType.TeamsAi;
298
- const isCopilot = options.projectType === ProjectType.Copilot;
299
- // Teams AI project doesn't care about auth, it will use authProvider for user to implement
300
- if (!isTeamsAi) {
301
- const authArray = Utils.getAuthArray(securities, spec);
302
- if (!Utils.isSupportedAuth(authArray, options)) {
303
- return false;
304
- }
305
- }
306
- const operationObject = pathObj[method];
307
- if (!options.allowMissingId && !operationObject.operationId) {
308
- return false;
309
- }
310
- const paramObject = operationObject.parameters;
311
- const requestBody = operationObject.requestBody;
312
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
313
- if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
314
- return false;
315
- }
316
- const responseJson = Utils.getResponseJson(operationObject, isTeamsAi);
317
- if (Object.keys(responseJson).length === 0) {
318
- return false;
319
- }
320
- // Teams AI project doesn't care about request parameters/body
321
- if (isTeamsAi) {
322
- return true;
323
- }
324
- let requestBodyParamResult = {
325
- requiredNum: 0,
326
- optionalNum: 0,
327
- isValid: true,
328
- };
329
- if (requestJsonBody) {
330
- const requestBodySchema = requestJsonBody.schema;
331
- if (isCopilot && requestBodySchema.type !== "object") {
332
- return false;
333
- }
334
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
335
- }
336
- if (!requestBodyParamResult.isValid) {
337
- return false;
338
- }
339
- const paramResult = Utils.checkParameters(paramObject, isCopilot);
340
- if (!paramResult.isValid) {
341
- return false;
319
+ if (options.allowMethods && !options.allowMethods.includes(method)) {
320
+ result.isValid = false;
321
+ result.reason.push(ErrorType.MethodNotAllowed);
322
+ return result;
323
+ }
324
+ const pathObj = spec.paths[path];
325
+ if (!pathObj || !pathObj[method]) {
326
+ result.isValid = false;
327
+ result.reason.push(ErrorType.UrlPathNotExist);
328
+ return result;
329
+ }
330
+ const securities = pathObj[method].security;
331
+ const isTeamsAi = options.projectType === ProjectType.TeamsAi;
332
+ const isCopilot = options.projectType === ProjectType.Copilot;
333
+ // Teams AI project doesn't care about auth, it will use authProvider for user to implement
334
+ if (!isTeamsAi) {
335
+ const authArray = Utils.getAuthArray(securities, spec);
336
+ const authCheckResult = Utils.isSupportedAuth(authArray, options);
337
+ if (!authCheckResult.isValid) {
338
+ result.reason.push(...authCheckResult.reason);
339
+ }
340
+ }
341
+ const operationObject = pathObj[method];
342
+ if (!options.allowMissingId && !operationObject.operationId) {
343
+ result.reason.push(ErrorType.MissingOperationId);
344
+ }
345
+ const rootServer = spec.servers && spec.servers[0];
346
+ const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
347
+ const operationServer = operationObject.servers && operationObject.servers[0];
348
+ const serverUrl = operationServer || methodServer || rootServer;
349
+ if (!serverUrl) {
350
+ result.reason.push(ErrorType.NoServerInformation);
351
+ }
352
+ else {
353
+ const serverValidateResult = Utils.checkServerUrl([serverUrl]);
354
+ result.reason.push(...serverValidateResult.map((item) => item.type));
355
+ }
356
+ const paramObject = operationObject.parameters;
357
+ const requestBody = operationObject.requestBody;
358
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
359
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
360
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
361
+ }
362
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject, isTeamsAi);
363
+ if (multipleMediaType && !isTeamsAi) {
364
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
365
+ }
366
+ else if (Object.keys(json).length === 0) {
367
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
368
+ }
369
+ // Teams AI project doesn't care about request parameters/body
370
+ if (!isTeamsAi) {
371
+ let requestBodyParamResult = {
372
+ requiredNum: 0,
373
+ optionalNum: 0,
374
+ isValid: true,
375
+ reason: [],
376
+ };
377
+ if (requestJsonBody) {
378
+ const requestBodySchema = requestJsonBody.schema;
379
+ if (isCopilot && requestBodySchema.type !== "object") {
380
+ result.reason.push(ErrorType.PostBodySchemaIsNotJson);
342
381
  }
343
- // Copilot support arbitrary parameters
344
- if (isCopilot) {
345
- return true;
382
+ requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
383
+ if (!requestBodyParamResult.isValid && requestBodyParamResult.reason) {
384
+ result.reason.push(...requestBodyParamResult.reason);
346
385
  }
347
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
348
- if (options.allowMultipleParameters &&
349
- requestBodyParamResult.requiredNum + paramResult.requiredNum <=
350
- ConstantString.SMERequiredParamsMaxNum) {
351
- return true;
386
+ }
387
+ const paramResult = Utils.checkParameters(paramObject, isCopilot);
388
+ if (!paramResult.isValid && paramResult.reason) {
389
+ result.reason.push(...paramResult.reason);
390
+ }
391
+ // Copilot support arbitrary parameters
392
+ if (!isCopilot && paramResult.isValid && requestBodyParamResult.isValid) {
393
+ const totalRequiredParams = requestBodyParamResult.requiredNum + paramResult.requiredNum;
394
+ const totalParams = totalRequiredParams + requestBodyParamResult.optionalNum + paramResult.optionalNum;
395
+ if (totalRequiredParams > 1) {
396
+ if (!options.allowMultipleParameters ||
397
+ totalRequiredParams > ConstantString.SMERequiredParamsMaxNum) {
398
+ result.reason.push(ErrorType.ExceededRequiredParamsLimit);
352
399
  }
353
- return false;
354
400
  }
355
- else if (requestBodyParamResult.requiredNum +
356
- requestBodyParamResult.optionalNum +
357
- paramResult.requiredNum +
358
- paramResult.optionalNum ===
359
- 0) {
360
- return false;
361
- }
362
- else {
363
- return true;
401
+ else if (totalParams === 0) {
402
+ result.reason.push(ErrorType.NoParameter);
364
403
  }
365
404
  }
366
405
  }
367
- return false;
406
+ if (result.reason.length > 0) {
407
+ result.isValid = false;
408
+ }
409
+ return result;
368
410
  }
369
- static isSupportedAuth(authSchemaArray, options) {
370
- if (authSchemaArray.length === 0) {
371
- return true;
411
+ static isSupportedAuth(authSchemeArray, options) {
412
+ if (authSchemeArray.length === 0) {
413
+ return { isValid: true, reason: [] };
372
414
  }
373
- if (options.allowAPIKeyAuth || options.allowOauth2) {
415
+ if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
374
416
  // Currently we don't support multiple auth in one operation
375
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
376
- return false;
417
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
418
+ return {
419
+ isValid: false,
420
+ reason: [ErrorType.MultipleAuthNotSupported],
421
+ };
377
422
  }
378
- for (const auths of authSchemaArray) {
423
+ for (const auths of authSchemeArray) {
379
424
  if (auths.length === 1) {
380
- if (!options.allowOauth2 &&
381
- options.allowAPIKeyAuth &&
382
- Utils.isAPIKeyAuth(auths[0].authSchema)) {
383
- return true;
384
- }
385
- else if (!options.allowAPIKeyAuth &&
386
- options.allowOauth2 &&
387
- Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema)) {
388
- return true;
389
- }
390
- else if (options.allowAPIKeyAuth &&
391
- options.allowOauth2 &&
392
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
393
- Utils.isOAuthWithAuthCodeFlow(auths[0].authSchema))) {
394
- return true;
425
+ if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
426
+ (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
427
+ (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
428
+ return { isValid: true, reason: [] };
395
429
  }
396
430
  }
397
431
  }
398
432
  }
399
- return false;
433
+ return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
434
+ }
435
+ static isBearerTokenAuth(authScheme) {
436
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
400
437
  }
401
- static isAPIKeyAuth(authSchema) {
402
- return authSchema.type === "apiKey";
438
+ static isAPIKeyAuth(authScheme) {
439
+ return authScheme.type === "apiKey";
403
440
  }
404
- static isOAuthWithAuthCodeFlow(authSchema) {
405
- if (authSchema.type === "oauth2" && authSchema.flows && authSchema.flows.authorizationCode) {
441
+ static isOAuthWithAuthCodeFlow(authScheme) {
442
+ if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
406
443
  return true;
407
444
  }
408
445
  return false;
@@ -418,7 +455,7 @@ class Utils {
418
455
  for (const name in security) {
419
456
  const auth = securitySchemas[name];
420
457
  authArray.push({
421
- authSchema: auth,
458
+ authScheme: auth,
422
459
  name: name,
423
460
  });
424
461
  }
@@ -436,11 +473,17 @@ class Utils {
436
473
  static getResponseJson(operationObject, isTeamsAiProject = false) {
437
474
  var _a, _b;
438
475
  let json = {};
476
+ let multipleMediaType = false;
439
477
  for (const code of ConstantString.ResponseCodeFor20X) {
440
478
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
441
479
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
480
+ multipleMediaType = false;
442
481
  json = responseObject.content["application/json"];
443
- if (!isTeamsAiProject && Utils.containMultipleMediaTypes(responseObject)) {
482
+ if (Utils.containMultipleMediaTypes(responseObject)) {
483
+ multipleMediaType = true;
484
+ if (isTeamsAiProject) {
485
+ break;
486
+ }
444
487
  json = {};
445
488
  }
446
489
  else {
@@ -448,7 +491,7 @@ class Utils {
448
491
  }
449
492
  }
450
493
  }
451
- return json;
494
+ return { json, multipleMediaType };
452
495
  }
453
496
  static convertPathToCamelCase(path) {
454
497
  const pathSegments = path.split(/[./{]/);
@@ -468,10 +511,10 @@ class Utils {
468
511
  return undefined;
469
512
  }
470
513
  }
471
- static resolveServerUrl(url) {
514
+ static resolveEnv(str) {
472
515
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
473
- let matches = placeHolderReg.exec(url);
474
- let newUrl = url;
516
+ let matches = placeHolderReg.exec(str);
517
+ let newStr = str;
475
518
  while (matches != null) {
476
519
  const envVar = matches[1];
477
520
  const envVal = process.env[envVar];
@@ -479,17 +522,17 @@ class Utils {
479
522
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
480
523
  }
481
524
  else {
482
- newUrl = newUrl.replace(matches[0], envVal);
525
+ newStr = newStr.replace(matches[0], envVal);
483
526
  }
484
- matches = placeHolderReg.exec(url);
527
+ matches = placeHolderReg.exec(str);
485
528
  }
486
- return newUrl;
529
+ return newStr;
487
530
  }
488
531
  static checkServerUrl(servers) {
489
532
  const errors = [];
490
533
  let serverUrl;
491
534
  try {
492
- serverUrl = Utils.resolveServerUrl(servers[0].url);
535
+ serverUrl = Utils.resolveEnv(servers[0].url);
493
536
  }
494
537
  catch (err) {
495
538
  errors.push({
@@ -520,6 +563,7 @@ class Utils {
520
563
  return errors;
521
564
  }
522
565
  static validateServer(spec, options) {
566
+ var _a;
523
567
  const errors = [];
524
568
  let hasTopLevelServers = false;
525
569
  let hasPathLevelServers = false;
@@ -540,7 +584,7 @@ class Utils {
540
584
  }
541
585
  for (const method in methods) {
542
586
  const operationObject = methods[method];
543
- if (Utils.isSupportedApi(method, path, spec, options)) {
587
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
544
588
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
545
589
  hasOperationLevelServers = true;
546
590
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -583,6 +627,7 @@ class Utils {
583
627
  Utils.updateParameterWithInputType(schema, parameter);
584
628
  }
585
629
  if (isRequired && schema.default === undefined) {
630
+ parameter.isRequired = true;
586
631
  requiredParams.push(parameter);
587
632
  }
588
633
  else {
@@ -646,6 +691,7 @@ class Utils {
646
691
  }
647
692
  if (param.in !== "header" && param.in !== "cookie") {
648
693
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
694
+ parameter.isRequired = true;
649
695
  requiredParams.push(parameter);
650
696
  }
651
697
  else {
@@ -665,13 +711,7 @@ class Utils {
665
711
  }
666
712
  }
667
713
  const operationId = operationItem.operationId;
668
- const parameters = [];
669
- if (requiredParams.length !== 0) {
670
- parameters.push(...requiredParams);
671
- }
672
- else {
673
- parameters.push(optionalParams[0]);
674
- }
714
+ const parameters = [...requiredParams, ...optionalParams];
675
715
  const command = {
676
716
  context: ["compose"],
677
717
  type: "query",
@@ -680,25 +720,23 @@ class Utils {
680
720
  parameters: parameters,
681
721
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
682
722
  };
683
- let warning = undefined;
684
- if (requiredParams.length === 0 && optionalParams.length > 1) {
685
- warning = {
686
- type: WarningType.OperationOnlyContainsOptionalParam,
687
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
688
- data: operationId,
689
- };
690
- }
691
- return [command, warning];
723
+ return command;
692
724
  }
693
- static listSupportedAPIs(spec, options) {
725
+ static listAPIs(spec, options) {
726
+ var _a;
694
727
  const paths = spec.paths;
695
728
  const result = {};
696
729
  for (const path in paths) {
697
730
  const methods = paths[path];
698
731
  for (const method in methods) {
699
- if (Utils.isSupportedApi(method, path, spec, options)) {
700
- const operationObject = methods[method];
701
- result[`${method.toUpperCase()} ${path}`] = operationObject;
732
+ const operationObject = methods[method];
733
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
734
+ const validateResult = Utils.isSupportedApi(method, path, spec, options);
735
+ result[`${method.toUpperCase()} ${path}`] = {
736
+ operation: operationObject,
737
+ isValid: validateResult.isValid,
738
+ reason: validateResult.reason,
739
+ };
702
740
  }
703
741
  }
704
742
  }
@@ -707,13 +745,13 @@ class Utils {
707
745
  static validateSpec(spec, parser, isSwaggerFile, options) {
708
746
  const errors = [];
709
747
  const warnings = [];
748
+ const apiMap = Utils.listAPIs(spec, options);
710
749
  if (isSwaggerFile) {
711
750
  warnings.push({
712
751
  type: WarningType.ConvertSwaggerToOpenAPI,
713
752
  content: ConstantString.ConvertSwaggerToOpenAPI,
714
753
  });
715
754
  }
716
- // Server validation
717
755
  const serverErrors = Utils.validateServer(spec, options);
718
756
  errors.push(...serverErrors);
719
757
  // Remote reference not supported
@@ -727,8 +765,8 @@ class Utils {
727
765
  });
728
766
  }
729
767
  // No supported API
730
- const apiMap = Utils.listSupportedAPIs(spec, options);
731
- if (Object.keys(apiMap).length === 0) {
768
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
769
+ if (validAPIs.length === 0) {
732
770
  errors.push({
733
771
  type: ErrorType.NoSupportedApi,
734
772
  content: ConstantString.NoSupportedApi,
@@ -737,8 +775,8 @@ class Utils {
737
775
  // OperationId missing
738
776
  const apisMissingOperationId = [];
739
777
  for (const key in apiMap) {
740
- const pathObjectItem = apiMap[key];
741
- if (!pathObjectItem.operationId) {
778
+ const { operation } = apiMap[key];
779
+ if (!operation.operationId) {
742
780
  apisMissingOperationId.push(key);
743
781
  }
744
782
  }
@@ -779,30 +817,50 @@ class Utils {
779
817
  }
780
818
  return safeRegistrationIdEnvName;
781
819
  }
820
+ static getAllAPICount(spec) {
821
+ let count = 0;
822
+ const paths = spec.paths;
823
+ for (const path in paths) {
824
+ const methods = paths[path];
825
+ for (const method in methods) {
826
+ if (ConstantString.AllOperationMethods.includes(method)) {
827
+ count++;
828
+ }
829
+ }
830
+ }
831
+ return count;
832
+ }
782
833
  }
783
834
 
784
835
  // Copyright (c) Microsoft Corporation.
785
836
  class SpecFilter {
786
837
  static specFilter(filter, unResolveSpec, resolvedSpec, options) {
838
+ var _a;
787
839
  try {
788
840
  const newSpec = Object.assign({}, unResolveSpec);
789
841
  const newPaths = {};
790
842
  for (const filterItem of filter) {
791
843
  const [method, path] = filterItem.split(" ");
792
844
  const methodName = method.toLowerCase();
793
- if (!Utils.isSupportedApi(methodName, path, resolvedSpec, options)) {
794
- continue;
795
- }
796
- if (!newPaths[path]) {
797
- newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
798
- for (const m of ConstantString.AllOperationMethods) {
799
- delete newPaths[path][m];
845
+ const pathObj = (_a = resolvedSpec.paths) === null || _a === void 0 ? void 0 : _a[path];
846
+ if (ConstantString.AllOperationMethods.includes(methodName) &&
847
+ pathObj &&
848
+ pathObj[methodName]) {
849
+ const validateResult = Utils.isSupportedApi(methodName, path, resolvedSpec, options);
850
+ if (!validateResult.isValid) {
851
+ continue;
852
+ }
853
+ if (!newPaths[path]) {
854
+ newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
855
+ for (const m of ConstantString.AllOperationMethods) {
856
+ delete newPaths[path][m];
857
+ }
858
+ }
859
+ newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
860
+ // Add the operationId if missing
861
+ if (!newPaths[path][methodName].operationId) {
862
+ newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
800
863
  }
801
- }
802
- newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
803
- // Add the operationId if missing
804
- if (!newPaths[path][methodName].operationId) {
805
- newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
806
864
  }
807
865
  }
808
866
  newSpec.paths = newPaths;
@@ -824,9 +882,10 @@ class ManifestUpdater {
824
882
  pluginFile: apiPluginRelativePath,
825
883
  },
826
884
  ];
885
+ const appName = this.removeEnvs(manifest.name.short);
827
886
  ManifestUpdater.updateManifestDescription(manifest, spec);
828
887
  const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
829
- const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, options);
888
+ const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
830
889
  return [manifest, apiPlugin];
831
890
  }
832
891
  static updateManifestDescription(manifest, spec) {
@@ -850,7 +909,7 @@ class ManifestUpdater {
850
909
  }
851
910
  return parameter;
852
911
  }
853
- static generatePluginManifestSchema(spec, specRelativePath, options) {
912
+ static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
854
913
  var _a, _b, _c;
855
914
  const functions = [];
856
915
  const functionNames = [];
@@ -915,7 +974,7 @@ class ManifestUpdater {
915
974
  }
916
975
  const apiPlugin = {
917
976
  schema_version: "v2",
918
- name_for_human: spec.info.title,
977
+ name_for_human: appName,
919
978
  description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
920
979
  functions: functions,
921
980
  runtimes: [
@@ -949,9 +1008,8 @@ class ManifestUpdater {
949
1008
  commands: commands,
950
1009
  };
951
1010
  if (authInfo) {
952
- let auth = authInfo.authSchema;
953
- if (Utils.isAPIKeyAuth(auth)) {
954
- auth = auth;
1011
+ const auth = authInfo.authScheme;
1012
+ if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
955
1013
  const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
956
1014
  composeExtension.authorization = {
957
1015
  authType: "apiSecretServiceAuth",
@@ -1000,16 +1058,26 @@ class ManifestUpdater {
1000
1058
  if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
1001
1059
  const operationItem = operations[method];
1002
1060
  if (operationItem) {
1003
- const [command, warning] = Utils.parseApiInfo(operationItem, options);
1061
+ const command = Utils.parseApiInfo(operationItem, options);
1062
+ if (command.parameters &&
1063
+ command.parameters.length >= 1 &&
1064
+ command.parameters.some((param) => param.isRequired)) {
1065
+ command.parameters = command.parameters.filter((param) => param.isRequired);
1066
+ }
1067
+ else if (command.parameters && command.parameters.length > 0) {
1068
+ command.parameters = [command.parameters[0]];
1069
+ warnings.push({
1070
+ type: WarningType.OperationOnlyContainsOptionalParam,
1071
+ content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
1072
+ data: command.id,
1073
+ });
1074
+ }
1004
1075
  if (adaptiveCardFolder) {
1005
1076
  const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
1006
1077
  command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
1007
1078
  ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
1008
1079
  : "";
1009
1080
  }
1010
- if (warning) {
1011
- warnings.push(warning);
1012
- }
1013
1081
  commands.push(command);
1014
1082
  }
1015
1083
  }
@@ -1023,13 +1091,22 @@ class ManifestUpdater {
1023
1091
  const relativePath = path.relative(path.dirname(from), to);
1024
1092
  return path.normalize(relativePath).replace(/\\/g, "/");
1025
1093
  }
1094
+ static removeEnvs(str) {
1095
+ const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
1096
+ const matches = placeHolderReg.exec(str);
1097
+ let newStr = str;
1098
+ if (matches != null) {
1099
+ newStr = newStr.replace(matches[0], "");
1100
+ }
1101
+ return newStr;
1102
+ }
1026
1103
  }
1027
1104
 
1028
1105
  // Copyright (c) Microsoft Corporation.
1029
1106
  class AdaptiveCardGenerator {
1030
1107
  static generateAdaptiveCard(operationItem) {
1031
1108
  try {
1032
- const json = Utils.getResponseJson(operationItem);
1109
+ const { json } = Utils.getResponseJson(operationItem);
1033
1110
  let cardBody = [];
1034
1111
  let schema = json.schema;
1035
1112
  let jsonPath = "$";
@@ -1289,6 +1366,7 @@ class SpecParser {
1289
1366
  allowMissingId: true,
1290
1367
  allowSwagger: true,
1291
1368
  allowAPIKeyAuth: false,
1369
+ allowBearerTokenAuth: false,
1292
1370
  allowMultipleParameters: false,
1293
1371
  allowOauth2: false,
1294
1372
  allowMethods: ["get", "post"],
@@ -1325,6 +1403,22 @@ class SpecParser {
1325
1403
  ],
1326
1404
  };
1327
1405
  }
1406
+ if (this.options.projectType === ProjectType.SME ||
1407
+ this.options.projectType === ProjectType.Copilot) {
1408
+ if (this.spec.openapi >= "3.1.0") {
1409
+ return {
1410
+ status: ValidationStatus.Error,
1411
+ warnings: [],
1412
+ errors: [
1413
+ {
1414
+ type: ErrorType.SpecVersionNotSupported,
1415
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
1416
+ data: this.spec.openapi,
1417
+ },
1418
+ ],
1419
+ };
1420
+ }
1421
+ }
1328
1422
  return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1329
1423
  }
1330
1424
  catch (err) {
@@ -1345,16 +1439,22 @@ class SpecParser {
1345
1439
  try {
1346
1440
  await this.loadSpec();
1347
1441
  const spec = this.spec;
1348
- const apiMap = this.getAllSupportedAPIs(spec);
1349
- const result = [];
1442
+ const apiMap = this.getAPIs(spec);
1443
+ const result = {
1444
+ APIs: [],
1445
+ allAPICount: 0,
1446
+ validAPICount: 0,
1447
+ };
1350
1448
  for (const apiKey in apiMap) {
1449
+ const { operation, isValid, reason } = apiMap[apiKey];
1450
+ const [method, path] = apiKey.split(" ");
1351
1451
  const apiResult = {
1352
1452
  api: "",
1353
1453
  server: "",
1354
1454
  operationId: "",
1455
+ isValid: isValid,
1456
+ reason: reason,
1355
1457
  };
1356
- const [method, path] = apiKey.split(" ");
1357
- const operation = apiMap[apiKey];
1358
1458
  const rootServer = spec.servers && spec.servers[0];
1359
1459
  const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
1360
1460
  const operationServer = operation.servers && operation.servers[0];
@@ -1362,7 +1462,7 @@ class SpecParser {
1362
1462
  if (!serverUrl) {
1363
1463
  throw new SpecParserError(ConstantString.NoServerInformation, ErrorType.NoServerInformation);
1364
1464
  }
1365
- apiResult.server = Utils.resolveServerUrl(serverUrl.url);
1465
+ apiResult.server = Utils.resolveEnv(serverUrl.url);
1366
1466
  let operationId = operation.operationId;
1367
1467
  if (!operationId) {
1368
1468
  operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
@@ -1371,13 +1471,15 @@ class SpecParser {
1371
1471
  const authArray = Utils.getAuthArray(operation.security, spec);
1372
1472
  for (const auths of authArray) {
1373
1473
  if (auths.length === 1) {
1374
- apiResult.auth = auths[0].authSchema;
1474
+ apiResult.auth = auths[0];
1375
1475
  break;
1376
1476
  }
1377
1477
  }
1378
1478
  apiResult.api = apiKey;
1379
- result.push(apiResult);
1479
+ result.APIs.push(apiResult);
1380
1480
  }
1481
+ result.allAPICount = result.APIs.length;
1482
+ result.validAPICount = result.APIs.filter((api) => api.isValid).length;
1381
1483
  return result;
1382
1484
  }
1383
1485
  catch (err) {
@@ -1469,15 +1571,18 @@ class SpecParser {
1469
1571
  const newSpecs = await this.getFilteredSpecs(filter, signal);
1470
1572
  const newUnResolvedSpec = newSpecs[0];
1471
1573
  const newSpec = newSpecs[1];
1472
- const authSet = new Set();
1473
1574
  let hasMultipleAuth = false;
1575
+ let authInfo = undefined;
1474
1576
  for (const url in newSpec.paths) {
1475
1577
  for (const method in newSpec.paths[url]) {
1476
1578
  const operation = newSpec.paths[url][method];
1477
1579
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1478
1580
  if (authArray && authArray.length > 0) {
1479
- authSet.add(authArray[0][0]);
1480
- if (authSet.size > 1) {
1581
+ const currentAuth = authArray[0][0];
1582
+ if (!authInfo) {
1583
+ authInfo = authArray[0][0];
1584
+ }
1585
+ else if (authInfo.name !== currentAuth.name) {
1481
1586
  hasMultipleAuth = true;
1482
1587
  break;
1483
1588
  }
@@ -1524,7 +1629,6 @@ class SpecParser {
1524
1629
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1525
1630
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1526
1631
  }
1527
- const authInfo = Array.from(authSet)[0];
1528
1632
  const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1529
1633
  await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1530
1634
  result.warnings.push(...warnings);
@@ -1550,11 +1654,11 @@ class SpecParser {
1550
1654
  this.spec = (await this.parser.dereference(clonedUnResolveSpec));
1551
1655
  }
1552
1656
  }
1553
- getAllSupportedAPIs(spec) {
1657
+ getAPIs(spec) {
1554
1658
  if (this.apiMap !== undefined) {
1555
1659
  return this.apiMap;
1556
1660
  }
1557
- const result = Utils.listSupportedAPIs(spec, this.options);
1661
+ const result = Utils.listAPIs(spec, this.options);
1558
1662
  this.apiMap = result;
1559
1663
  return result;
1560
1664
  }