@microsoft/m365-spec-parser 0.1.1-alpha.78701ec6a.0 → 0.1.1-alpha.87f45d762.0

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