@microsoft/m365-spec-parser 0.1.1-alpha.78701ec6a.0 → 0.1.1-alpha.7fe3da414.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,8 @@ 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;
185
212
 
186
213
  // Copyright (c) Microsoft Corporation.
187
214
  class SpecParserError extends Error {
@@ -193,11 +220,23 @@ class SpecParserError extends Error {
193
220
 
194
221
  // Copyright (c) Microsoft Corporation.
195
222
  class Utils {
196
- static checkParameters(paramObject) {
223
+ static hasNestedObjectInSchema(schema) {
224
+ if (schema.type === "object") {
225
+ for (const property in schema.properties) {
226
+ const nestedSchema = schema.properties[property];
227
+ if (nestedSchema.type === "object") {
228
+ return true;
229
+ }
230
+ }
231
+ }
232
+ return false;
233
+ }
234
+ static checkParameters(paramObject, isCopilot) {
197
235
  const paramResult = {
198
236
  requiredNum: 0,
199
237
  optionalNum: 0,
200
238
  isValid: true,
239
+ reason: [],
201
240
  };
202
241
  if (!paramObject) {
203
242
  return paramResult;
@@ -205,10 +244,25 @@ class Utils {
205
244
  for (let i = 0; i < paramObject.length; i++) {
206
245
  const param = paramObject[i];
207
246
  const schema = param.schema;
247
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
248
+ paramResult.isValid = false;
249
+ paramResult.reason.push(exports.ErrorType.ParamsContainsNestedObject);
250
+ continue;
251
+ }
208
252
  const isRequiredWithoutDefault = param.required && schema.default === undefined;
253
+ if (isCopilot) {
254
+ if (isRequiredWithoutDefault) {
255
+ paramResult.requiredNum = paramResult.requiredNum + 1;
256
+ }
257
+ else {
258
+ paramResult.optionalNum = paramResult.optionalNum + 1;
259
+ }
260
+ continue;
261
+ }
209
262
  if (param.in === "header" || param.in === "cookie") {
210
263
  if (isRequiredWithoutDefault) {
211
264
  paramResult.isValid = false;
265
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
212
266
  }
213
267
  continue;
214
268
  }
@@ -218,6 +272,7 @@ class Utils {
218
272
  schema.type !== "integer") {
219
273
  if (isRequiredWithoutDefault) {
220
274
  paramResult.isValid = false;
275
+ paramResult.reason.push(exports.ErrorType.ParamsContainRequiredUnsupportedSchema);
221
276
  }
222
277
  continue;
223
278
  }
@@ -232,17 +287,23 @@ class Utils {
232
287
  }
233
288
  return paramResult;
234
289
  }
235
- static checkPostBody(schema, isRequired = false) {
290
+ static checkPostBody(schema, isRequired = false, isCopilot = false) {
236
291
  var _a;
237
292
  const paramResult = {
238
293
  requiredNum: 0,
239
294
  optionalNum: 0,
240
295
  isValid: true,
296
+ reason: [],
241
297
  };
242
298
  if (Object.keys(schema).length === 0) {
243
299
  return paramResult;
244
300
  }
245
301
  const isRequiredWithoutDefault = isRequired && schema.default === undefined;
302
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
303
+ paramResult.isValid = false;
304
+ paramResult.reason = [exports.ErrorType.RequestBodyContainsNestedObject];
305
+ return paramResult;
306
+ }
246
307
  if (schema.type === "string" ||
247
308
  schema.type === "integer" ||
248
309
  schema.type === "boolean" ||
@@ -261,19 +322,24 @@ class Utils {
261
322
  if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
262
323
  isRequired = true;
263
324
  }
264
- const result = Utils.checkPostBody(properties[property], isRequired);
325
+ const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
265
326
  paramResult.requiredNum += result.requiredNum;
266
327
  paramResult.optionalNum += result.optionalNum;
267
328
  paramResult.isValid = paramResult.isValid && result.isValid;
329
+ paramResult.reason.push(...result.reason);
268
330
  }
269
331
  }
270
332
  else {
271
- if (isRequiredWithoutDefault) {
333
+ if (isRequiredWithoutDefault && !isCopilot) {
272
334
  paramResult.isValid = false;
335
+ paramResult.reason.push(exports.ErrorType.PostBodyContainsRequiredUnsupportedSchema);
273
336
  }
274
337
  }
275
338
  return paramResult;
276
339
  }
340
+ static containMultipleMediaTypes(bodyObject) {
341
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
342
+ }
277
343
  /**
278
344
  * Checks if the given API is supported.
279
345
  * @param {string} method - The HTTP method of the API.
@@ -288,106 +354,137 @@ class Utils {
288
354
  * 5. response body should be “application/json” and not empty, and response code should be 20X
289
355
  * 6. only support request body with “application/json” content type
290
356
  */
291
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
292
- const pathObj = spec.paths[path];
357
+ static isSupportedApi(method, path, spec, options) {
358
+ var _a;
359
+ const result = { isValid: true, reason: [] };
293
360
  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;
361
+ if (options.allowMethods && !options.allowMethods.includes(method)) {
362
+ result.isValid = false;
363
+ result.reason.push(exports.ErrorType.MethodNotAllowed);
364
+ return result;
365
+ }
366
+ const pathObj = spec.paths[path];
367
+ if (!pathObj || !pathObj[method]) {
368
+ result.isValid = false;
369
+ result.reason.push(exports.ErrorType.UrlPathNotExist);
370
+ return result;
371
+ }
372
+ const securities = pathObj[method].security;
373
+ const isTeamsAi = options.projectType === exports.ProjectType.TeamsAi;
374
+ const isCopilot = options.projectType === exports.ProjectType.Copilot;
375
+ // Teams AI project doesn't care about auth, it will use authProvider for user to implement
376
+ if (!isTeamsAi) {
377
+ const authArray = Utils.getAuthArray(securities, spec);
378
+ const authCheckResult = Utils.isSupportedAuth(authArray, options);
379
+ if (!authCheckResult.isValid) {
380
+ result.reason.push(...authCheckResult.reason);
381
+ }
382
+ }
383
+ const operationObject = pathObj[method];
384
+ if (!options.allowMissingId && !operationObject.operationId) {
385
+ result.reason.push(exports.ErrorType.MissingOperationId);
386
+ }
387
+ const rootServer = spec.servers && spec.servers[0];
388
+ const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
389
+ const operationServer = operationObject.servers && operationObject.servers[0];
390
+ const serverUrl = operationServer || methodServer || rootServer;
391
+ if (!serverUrl) {
392
+ result.reason.push(exports.ErrorType.NoServerInformation);
393
+ }
394
+ else {
395
+ const serverValidateResult = Utils.checkServerUrl([serverUrl]);
396
+ result.reason.push(...serverValidateResult.map((item) => item.type));
397
+ }
398
+ const paramObject = operationObject.parameters;
399
+ const requestBody = operationObject.requestBody;
400
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
401
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
402
+ result.reason.push(exports.ErrorType.PostBodyContainMultipleMediaTypes);
403
+ }
404
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject, isTeamsAi);
405
+ if (multipleMediaType && !isTeamsAi) {
406
+ result.reason.push(exports.ErrorType.ResponseContainMultipleMediaTypes);
407
+ }
408
+ else if (Object.keys(json).length === 0) {
409
+ result.reason.push(exports.ErrorType.ResponseJsonIsEmpty);
410
+ }
411
+ // Teams AI project doesn't care about request parameters/body
412
+ if (!isTeamsAi) {
413
+ let requestBodyParamResult = {
414
+ requiredNum: 0,
415
+ optionalNum: 0,
416
+ isValid: true,
417
+ reason: [],
418
+ };
419
+ if (requestJsonBody) {
420
+ const requestBodySchema = requestJsonBody.schema;
421
+ if (isCopilot && requestBodySchema.type !== "object") {
422
+ result.reason.push(exports.ErrorType.PostBodySchemaIsNotJson);
328
423
  }
329
- const paramResult = Utils.checkParameters(paramObject);
330
- if (!paramResult.isValid) {
331
- return false;
424
+ requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
425
+ if (!requestBodyParamResult.isValid && requestBodyParamResult.reason) {
426
+ result.reason.push(...requestBodyParamResult.reason);
332
427
  }
333
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
334
- if (allowMultipleParameters &&
335
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
336
- return true;
428
+ }
429
+ const paramResult = Utils.checkParameters(paramObject, isCopilot);
430
+ if (!paramResult.isValid && paramResult.reason) {
431
+ result.reason.push(...paramResult.reason);
432
+ }
433
+ // Copilot support arbitrary parameters
434
+ if (!isCopilot && paramResult.isValid && requestBodyParamResult.isValid) {
435
+ const totalRequiredParams = requestBodyParamResult.requiredNum + paramResult.requiredNum;
436
+ const totalParams = totalRequiredParams + requestBodyParamResult.optionalNum + paramResult.optionalNum;
437
+ if (totalRequiredParams > 1) {
438
+ if (!options.allowMultipleParameters ||
439
+ totalRequiredParams > ConstantString.SMERequiredParamsMaxNum) {
440
+ result.reason.push(exports.ErrorType.ExceededRequiredParamsLimit);
337
441
  }
338
- return false;
339
- }
340
- else if (requestBodyParamResult.requiredNum +
341
- requestBodyParamResult.optionalNum +
342
- paramResult.requiredNum +
343
- paramResult.optionalNum ===
344
- 0) {
345
- return false;
346
442
  }
347
- else {
348
- return true;
443
+ else if (totalParams === 0) {
444
+ result.reason.push(exports.ErrorType.NoParameter);
349
445
  }
350
446
  }
351
447
  }
352
- return false;
448
+ if (result.reason.length > 0) {
449
+ result.isValid = false;
450
+ }
451
+ return result;
353
452
  }
354
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
355
- if (authSchemaArray.length === 0) {
356
- return true;
453
+ static isSupportedAuth(authSchemeArray, options) {
454
+ if (authSchemeArray.length === 0) {
455
+ return { isValid: true, reason: [] };
357
456
  }
358
- if (allowAPIKeyAuth || allowOauth2) {
457
+ if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
359
458
  // Currently we don't support multiple auth in one operation
360
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
361
- return false;
459
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
460
+ return {
461
+ isValid: false,
462
+ reason: [exports.ErrorType.MultipleAuthNotSupported],
463
+ };
362
464
  }
363
- for (const auths of authSchemaArray) {
465
+ for (const auths of authSchemeArray) {
364
466
  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;
467
+ if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
468
+ (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
469
+ (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
470
+ return { isValid: true, reason: [] };
378
471
  }
379
472
  }
380
473
  }
381
474
  }
382
- return false;
475
+ return { isValid: false, reason: [exports.ErrorType.AuthTypeIsNotSupported] };
383
476
  }
384
- static isAPIKeyAuth(authSchema) {
385
- return authSchema.type === "apiKey";
477
+ static isBearerTokenAuth(authScheme) {
478
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
386
479
  }
387
- static isBearerTokenAuth(authSchema) {
388
- return (authSchema.type === "oauth2" ||
389
- authSchema.type === "openIdConnect" ||
390
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
480
+ static isAPIKeyAuth(authScheme) {
481
+ return authScheme.type === "apiKey";
482
+ }
483
+ static isOAuthWithAuthCodeFlow(authScheme) {
484
+ if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
485
+ return true;
486
+ }
487
+ return false;
391
488
  }
392
489
  static getAuthArray(securities, spec) {
393
490
  var _a;
@@ -400,7 +497,7 @@ class Utils {
400
497
  for (const name in security) {
401
498
  const auth = securitySchemas[name];
402
499
  authArray.push({
403
- authSchema: auth,
500
+ authScheme: auth,
404
501
  name: name,
405
502
  });
406
503
  }
@@ -415,21 +512,28 @@ class Utils {
415
512
  static updateFirstLetter(str) {
416
513
  return str.charAt(0).toUpperCase() + str.slice(1);
417
514
  }
418
- static getResponseJson(operationObject) {
515
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
419
516
  var _a, _b;
420
517
  let json = {};
518
+ let multipleMediaType = false;
421
519
  for (const code of ConstantString.ResponseCodeFor20X) {
422
520
  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
521
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
522
+ multipleMediaType = false;
428
523
  json = responseObject.content["application/json"];
429
- break;
524
+ if (Utils.containMultipleMediaTypes(responseObject)) {
525
+ multipleMediaType = true;
526
+ if (isTeamsAiProject) {
527
+ break;
528
+ }
529
+ json = {};
530
+ }
531
+ else {
532
+ break;
533
+ }
430
534
  }
431
535
  }
432
- return json;
536
+ return { json, multipleMediaType };
433
537
  }
434
538
  static convertPathToCamelCase(path) {
435
539
  const pathSegments = path.split(/[./{]/);
@@ -449,10 +553,10 @@ class Utils {
449
553
  return undefined;
450
554
  }
451
555
  }
452
- static resolveServerUrl(url) {
556
+ static resolveEnv(str) {
453
557
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
454
- let matches = placeHolderReg.exec(url);
455
- let newUrl = url;
558
+ let matches = placeHolderReg.exec(str);
559
+ let newStr = str;
456
560
  while (matches != null) {
457
561
  const envVar = matches[1];
458
562
  const envVal = process.env[envVar];
@@ -460,17 +564,17 @@ class Utils {
460
564
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
461
565
  }
462
566
  else {
463
- newUrl = newUrl.replace(matches[0], envVal);
567
+ newStr = newStr.replace(matches[0], envVal);
464
568
  }
465
- matches = placeHolderReg.exec(url);
569
+ matches = placeHolderReg.exec(str);
466
570
  }
467
- return newUrl;
571
+ return newStr;
468
572
  }
469
573
  static checkServerUrl(servers) {
470
574
  const errors = [];
471
575
  let serverUrl;
472
576
  try {
473
- serverUrl = Utils.resolveServerUrl(servers[0].url);
577
+ serverUrl = Utils.resolveEnv(servers[0].url);
474
578
  }
475
579
  catch (err) {
476
580
  errors.push({
@@ -500,7 +604,8 @@ class Utils {
500
604
  }
501
605
  return errors;
502
606
  }
503
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
607
+ static validateServer(spec, options) {
608
+ var _a;
504
609
  const errors = [];
505
610
  let hasTopLevelServers = false;
506
611
  let hasPathLevelServers = false;
@@ -521,7 +626,7 @@ class Utils {
521
626
  }
522
627
  for (const method in methods) {
523
628
  const operationObject = methods[method];
524
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
629
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
525
630
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
526
631
  hasOperationLevelServers = true;
527
632
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -564,6 +669,7 @@ class Utils {
564
669
  Utils.updateParameterWithInputType(schema, parameter);
565
670
  }
566
671
  if (isRequired && schema.default === undefined) {
672
+ parameter.isRequired = true;
567
673
  requiredParams.push(parameter);
568
674
  }
569
675
  else {
@@ -608,7 +714,7 @@ class Utils {
608
714
  param.value = schema.default;
609
715
  }
610
716
  }
611
- static parseApiInfo(operationItem, allowMultipleParameters) {
717
+ static parseApiInfo(operationItem, options) {
612
718
  var _a, _b;
613
719
  const requiredParams = [];
614
720
  const optionalParams = [];
@@ -622,11 +728,12 @@ class Utils {
622
728
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
623
729
  };
624
730
  const schema = param.schema;
625
- if (allowMultipleParameters && schema) {
731
+ if (options.allowMultipleParameters && schema) {
626
732
  Utils.updateParameterWithInputType(schema, parameter);
627
733
  }
628
734
  if (param.in !== "header" && param.in !== "cookie") {
629
735
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
736
+ parameter.isRequired = true;
630
737
  requiredParams.push(parameter);
631
738
  }
632
739
  else {
@@ -640,7 +747,7 @@ class Utils {
640
747
  const requestJson = requestBody.content["application/json"];
641
748
  if (Object.keys(requestJson).length !== 0) {
642
749
  const schema = requestJson.schema;
643
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
750
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
644
751
  requiredParams.push(...requiredP);
645
752
  optionalParams.push(...optionalP);
646
753
  }
@@ -671,32 +778,37 @@ class Utils {
671
778
  }
672
779
  return [command, warning];
673
780
  }
674
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
781
+ static listAPIs(spec, options) {
782
+ var _a;
675
783
  const paths = spec.paths;
676
784
  const result = {};
677
785
  for (const path in paths) {
678
786
  const methods = paths[path];
679
787
  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;
788
+ const operationObject = methods[method];
789
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
790
+ const validateResult = Utils.isSupportedApi(method, path, spec, options);
791
+ result[`${method.toUpperCase()} ${path}`] = {
792
+ operation: operationObject,
793
+ isValid: validateResult.isValid,
794
+ reason: validateResult.reason,
795
+ };
684
796
  }
685
797
  }
686
798
  }
687
799
  return result;
688
800
  }
689
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
801
+ static validateSpec(spec, parser, isSwaggerFile, options) {
690
802
  const errors = [];
691
803
  const warnings = [];
804
+ const apiMap = Utils.listAPIs(spec, options);
692
805
  if (isSwaggerFile) {
693
806
  warnings.push({
694
807
  type: exports.WarningType.ConvertSwaggerToOpenAPI,
695
808
  content: ConstantString.ConvertSwaggerToOpenAPI,
696
809
  });
697
810
  }
698
- // Server validation
699
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
811
+ const serverErrors = Utils.validateServer(spec, options);
700
812
  errors.push(...serverErrors);
701
813
  // Remote reference not supported
702
814
  const refPaths = parser.$refs.paths();
@@ -709,8 +821,8 @@ class Utils {
709
821
  });
710
822
  }
711
823
  // No supported API
712
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
713
- if (Object.keys(apiMap).length === 0) {
824
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
825
+ if (validAPIs.length === 0) {
714
826
  errors.push({
715
827
  type: exports.ErrorType.NoSupportedApi,
716
828
  content: ConstantString.NoSupportedApi,
@@ -719,8 +831,8 @@ class Utils {
719
831
  // OperationId missing
720
832
  const apisMissingOperationId = [];
721
833
  for (const key in apiMap) {
722
- const pathObjectItem = apiMap[key];
723
- if (!pathObjectItem.operationId) {
834
+ const { operation } = apiMap[key];
835
+ if (!operation.operationId) {
724
836
  apisMissingOperationId.push(key);
725
837
  }
726
838
  }
@@ -761,30 +873,50 @@ class Utils {
761
873
  }
762
874
  return safeRegistrationIdEnvName;
763
875
  }
876
+ static getAllAPICount(spec) {
877
+ let count = 0;
878
+ const paths = spec.paths;
879
+ for (const path in paths) {
880
+ const methods = paths[path];
881
+ for (const method in methods) {
882
+ if (ConstantString.AllOperationMethods.includes(method)) {
883
+ count++;
884
+ }
885
+ }
886
+ }
887
+ return count;
888
+ }
764
889
  }
765
890
 
766
891
  // Copyright (c) Microsoft Corporation.
767
892
  class SpecFilter {
768
- static specFilter(filter, unResolveSpec, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
893
+ static specFilter(filter, unResolveSpec, resolvedSpec, options) {
894
+ var _a;
769
895
  try {
770
896
  const newSpec = Object.assign({}, unResolveSpec);
771
897
  const newPaths = {};
772
898
  for (const filterItem of filter) {
773
899
  const [method, path] = filterItem.split(" ");
774
900
  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];
901
+ const pathObj = (_a = resolvedSpec.paths) === null || _a === void 0 ? void 0 : _a[path];
902
+ if (ConstantString.AllOperationMethods.includes(methodName) &&
903
+ pathObj &&
904
+ pathObj[methodName]) {
905
+ const validateResult = Utils.isSupportedApi(methodName, path, resolvedSpec, options);
906
+ if (!validateResult.isValid) {
907
+ continue;
908
+ }
909
+ if (!newPaths[path]) {
910
+ newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
911
+ for (const m of ConstantString.AllOperationMethods) {
912
+ delete newPaths[path][m];
913
+ }
914
+ }
915
+ newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
916
+ // Add the operationId if missing
917
+ if (!newPaths[path][methodName].operationId) {
918
+ newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
782
919
  }
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
920
  }
789
921
  }
790
922
  newSpec.paths = newPaths;
@@ -798,47 +930,171 @@ class SpecFilter {
798
930
 
799
931
  // Copyright (c) Microsoft Corporation.
800
932
  class ManifestUpdater {
801
- static updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, spec, allowMultipleParameters, auth) {
933
+ static updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
934
+ return __awaiter(this, void 0, void 0, function* () {
935
+ const manifest = yield fs__default['default'].readJSON(manifestPath);
936
+ const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
937
+ manifest.plugins = [
938
+ {
939
+ pluginFile: apiPluginRelativePath,
940
+ },
941
+ ];
942
+ const appName = this.removeEnvs(manifest.name.short);
943
+ ManifestUpdater.updateManifestDescription(manifest, spec);
944
+ const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
945
+ const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
946
+ return [manifest, apiPlugin];
947
+ });
948
+ }
949
+ static updateManifestDescription(manifest, spec) {
802
950
  var _a, _b;
951
+ manifest.description = {
952
+ short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
953
+ 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),
954
+ };
955
+ }
956
+ static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
957
+ let parameter;
958
+ if (schema.type === "string" ||
959
+ schema.type === "boolean" ||
960
+ schema.type === "integer" ||
961
+ schema.type === "number" ||
962
+ schema.type === "array") {
963
+ parameter = schema;
964
+ }
965
+ else {
966
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), exports.ErrorType.UpdateManifestFailed);
967
+ }
968
+ return parameter;
969
+ }
970
+ static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
971
+ var _a, _b, _c;
972
+ const functions = [];
973
+ const functionNames = [];
974
+ const paths = spec.paths;
975
+ for (const pathUrl in paths) {
976
+ const pathItem = paths[pathUrl];
977
+ if (pathItem) {
978
+ const operations = pathItem;
979
+ for (const method in operations) {
980
+ if (options.allowMethods.includes(method)) {
981
+ const operationItem = operations[method];
982
+ if (operationItem) {
983
+ const operationId = operationItem.operationId;
984
+ const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
985
+ const paramObject = operationItem.parameters;
986
+ const requestBody = operationItem.requestBody;
987
+ const parameters = {
988
+ type: "object",
989
+ properties: {},
990
+ required: [],
991
+ };
992
+ if (paramObject) {
993
+ for (let i = 0; i < paramObject.length; i++) {
994
+ const param = paramObject[i];
995
+ const schema = param.schema;
996
+ parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
997
+ if (param.required) {
998
+ parameters.required.push(param.name);
999
+ }
1000
+ if (!parameters.properties[param.name].description) {
1001
+ parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
1002
+ }
1003
+ }
1004
+ }
1005
+ if (requestBody) {
1006
+ const requestJsonBody = requestBody.content["application/json"];
1007
+ const requestBodySchema = requestJsonBody.schema;
1008
+ if (requestBodySchema.type === "object") {
1009
+ if (requestBodySchema.required) {
1010
+ parameters.required.push(...requestBodySchema.required);
1011
+ }
1012
+ for (const property in requestBodySchema.properties) {
1013
+ const schema = requestBodySchema.properties[property];
1014
+ parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
1015
+ }
1016
+ }
1017
+ else {
1018
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
1019
+ }
1020
+ }
1021
+ const funcObj = {
1022
+ name: operationId,
1023
+ description: description,
1024
+ parameters: parameters,
1025
+ };
1026
+ functions.push(funcObj);
1027
+ functionNames.push(operationId);
1028
+ }
1029
+ }
1030
+ }
1031
+ }
1032
+ }
1033
+ const apiPlugin = {
1034
+ schema_version: "v2",
1035
+ name_for_human: appName,
1036
+ description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
1037
+ functions: functions,
1038
+ runtimes: [
1039
+ {
1040
+ type: "OpenApi",
1041
+ auth: {
1042
+ type: "none", // TODO, support auth in the future
1043
+ },
1044
+ spec: {
1045
+ url: specRelativePath,
1046
+ },
1047
+ run_for_functions: functionNames,
1048
+ },
1049
+ ],
1050
+ };
1051
+ return apiPlugin;
1052
+ }
1053
+ static updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
803
1054
  return __awaiter(this, void 0, void 0, function* () {
804
1055
  try {
805
1056
  const originalManifest = yield fs__default['default'].readJSON(manifestPath);
806
1057
  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
- };
1058
+ updatedPart.composeExtensions = [];
1059
+ let warnings = [];
1060
+ if (options.projectType === exports.ProjectType.SME) {
1061
+ const updateResult = yield ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
1062
+ const commands = updateResult[0];
1063
+ warnings = updateResult[1];
1064
+ const composeExtension = {
1065
+ composeExtensionType: "apiBased",
1066
+ apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
1067
+ commands: commands,
1068
+ };
1069
+ if (authInfo) {
1070
+ const auth = authInfo.authScheme;
1071
+ if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1072
+ const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
1073
+ composeExtension.authorization = {
1074
+ authType: "apiSecretServiceAuth",
1075
+ apiSecretServiceAuthConfiguration: {
1076
+ apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
1077
+ },
1078
+ };
1079
+ }
1080
+ else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
1081
+ const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
1082
+ composeExtension.authorization = {
1083
+ authType: "oAuth2.0",
1084
+ oAuthConfiguration: {
1085
+ oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
1086
+ },
1087
+ };
1088
+ updatedPart.webApplicationInfo = {
1089
+ id: "${{AAD_APP_CLIENT_ID}}",
1090
+ resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
1091
+ };
1092
+ }
835
1093
  }
1094
+ updatedPart.composeExtensions = [composeExtension];
836
1095
  }
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];
1096
+ updatedPart.description = originalManifest.description;
1097
+ ManifestUpdater.updateManifestDescription(updatedPart, spec);
842
1098
  const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
843
1099
  return [updatedManifest, warnings];
844
1100
  }
@@ -847,7 +1103,8 @@ class ManifestUpdater {
847
1103
  }
848
1104
  });
849
1105
  }
850
- static generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters) {
1106
+ static generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
1107
+ var _a;
851
1108
  return __awaiter(this, void 0, void 0, function* () {
852
1109
  const paths = spec.paths;
853
1110
  const commands = [];
@@ -859,14 +1116,16 @@ class ManifestUpdater {
859
1116
  const operations = pathItem;
860
1117
  // Currently only support GET and POST method
861
1118
  for (const method in operations) {
862
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1119
+ if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
863
1120
  const operationItem = operations[method];
864
1121
  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
- : "";
1122
+ const [command, warning] = Utils.parseApiInfo(operationItem, options);
1123
+ if (adaptiveCardFolder) {
1124
+ const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
1125
+ command.apiResponseRenderingTemplateFile = (yield fs__default['default'].pathExists(adaptiveCardPath))
1126
+ ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
1127
+ : "";
1128
+ }
870
1129
  if (warning) {
871
1130
  warnings.push(warning);
872
1131
  }
@@ -884,13 +1143,22 @@ class ManifestUpdater {
884
1143
  const relativePath = path__default['default'].relative(path__default['default'].dirname(from), to);
885
1144
  return path__default['default'].normalize(relativePath).replace(/\\/g, "/");
886
1145
  }
1146
+ static removeEnvs(str) {
1147
+ const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
1148
+ const matches = placeHolderReg.exec(str);
1149
+ let newStr = str;
1150
+ if (matches != null) {
1151
+ newStr = newStr.replace(matches[0], "");
1152
+ }
1153
+ return newStr;
1154
+ }
887
1155
  }
888
1156
 
889
1157
  // Copyright (c) Microsoft Corporation.
890
1158
  class AdaptiveCardGenerator {
891
1159
  static generateAdaptiveCard(operationItem) {
892
1160
  try {
893
- const json = Utils.getResponseJson(operationItem);
1161
+ const { json } = Utils.getResponseJson(operationItem);
894
1162
  let cardBody = [];
895
1163
  let schema = json.schema;
896
1164
  let jsonPath = "$";
@@ -1150,8 +1418,11 @@ class SpecParser {
1150
1418
  allowMissingId: true,
1151
1419
  allowSwagger: true,
1152
1420
  allowAPIKeyAuth: false,
1421
+ allowBearerTokenAuth: false,
1153
1422
  allowMultipleParameters: false,
1154
1423
  allowOauth2: false,
1424
+ allowMethods: ["get", "post"],
1425
+ projectType: exports.ProjectType.SME,
1155
1426
  };
1156
1427
  this.pathOrSpec = pathOrDoc;
1157
1428
  this.parser = new SwaggerParser__default['default']();
@@ -1185,7 +1456,23 @@ class SpecParser {
1185
1456
  ],
1186
1457
  };
1187
1458
  }
1188
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1459
+ if (this.options.projectType === exports.ProjectType.SME ||
1460
+ this.options.projectType === exports.ProjectType.Copilot) {
1461
+ if (this.spec.openapi >= "3.1.0") {
1462
+ return {
1463
+ status: exports.ValidationStatus.Error,
1464
+ warnings: [],
1465
+ errors: [
1466
+ {
1467
+ type: exports.ErrorType.SpecVersionNotSupported,
1468
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
1469
+ data: this.spec.openapi,
1470
+ },
1471
+ ],
1472
+ };
1473
+ }
1474
+ }
1475
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1189
1476
  }
1190
1477
  catch (err) {
1191
1478
  throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
@@ -1209,16 +1496,22 @@ class SpecParser {
1209
1496
  try {
1210
1497
  yield this.loadSpec();
1211
1498
  const spec = this.spec;
1212
- const apiMap = this.getAllSupportedAPIs(spec);
1213
- const result = [];
1499
+ const apiMap = this.getAPIs(spec);
1500
+ const result = {
1501
+ APIs: [],
1502
+ allAPICount: 0,
1503
+ validAPICount: 0,
1504
+ };
1214
1505
  for (const apiKey in apiMap) {
1506
+ const { operation, isValid, reason } = apiMap[apiKey];
1507
+ const [method, path] = apiKey.split(" ");
1215
1508
  const apiResult = {
1216
1509
  api: "",
1217
1510
  server: "",
1218
1511
  operationId: "",
1512
+ isValid: isValid,
1513
+ reason: reason,
1219
1514
  };
1220
- const [method, path] = apiKey.split(" ");
1221
- const operation = apiMap[apiKey];
1222
1515
  const rootServer = spec.servers && spec.servers[0];
1223
1516
  const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
1224
1517
  const operationServer = operation.servers && operation.servers[0];
@@ -1226,7 +1519,7 @@ class SpecParser {
1226
1519
  if (!serverUrl) {
1227
1520
  throw new SpecParserError(ConstantString.NoServerInformation, exports.ErrorType.NoServerInformation);
1228
1521
  }
1229
- apiResult.server = Utils.resolveServerUrl(serverUrl.url);
1522
+ apiResult.server = Utils.resolveEnv(serverUrl.url);
1230
1523
  let operationId = operation.operationId;
1231
1524
  if (!operationId) {
1232
1525
  operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
@@ -1235,13 +1528,15 @@ class SpecParser {
1235
1528
  const authArray = Utils.getAuthArray(operation.security, spec);
1236
1529
  for (const auths of authArray) {
1237
1530
  if (auths.length === 1) {
1238
- apiResult.auth = auths[0].authSchema;
1531
+ apiResult.auth = auths[0];
1239
1532
  break;
1240
1533
  }
1241
1534
  }
1242
1535
  apiResult.api = apiKey;
1243
- result.push(apiResult);
1536
+ result.APIs.push(apiResult);
1244
1537
  }
1538
+ result.allAPICount = result.APIs.length;
1539
+ result.validAPICount = result.APIs.filter((api) => api.isValid).length;
1245
1540
  return result;
1246
1541
  }
1247
1542
  catch (err) {
@@ -1252,49 +1547,113 @@ class SpecParser {
1252
1547
  }
1253
1548
  });
1254
1549
  }
1550
+ /**
1551
+ * Generate specs according to the filters.
1552
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1553
+ */
1554
+ getFilteredSpecs(filter, signal) {
1555
+ return __awaiter(this, void 0, void 0, function* () {
1556
+ try {
1557
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1558
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1559
+ }
1560
+ yield this.loadSpec();
1561
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1562
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1563
+ }
1564
+ const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
1565
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1566
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1567
+ }
1568
+ const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
1569
+ return [newUnResolvedSpec, newSpec];
1570
+ }
1571
+ catch (err) {
1572
+ if (err instanceof SpecParserError) {
1573
+ throw err;
1574
+ }
1575
+ throw new SpecParserError(err.toString(), exports.ErrorType.GetSpecFailed);
1576
+ }
1577
+ });
1578
+ }
1255
1579
  /**
1256
1580
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1257
1581
  * @param manifestPath A file path of the Teams app manifest file to update.
1258
1582
  * @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
1583
  * @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.
1584
+ * @param pluginFilePath File path of the api plugin file to generate.
1261
1585
  */
1262
- generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1586
+ generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1263
1587
  return __awaiter(this, void 0, void 0, function* () {
1264
1588
  const result = {
1265
1589
  allSuccess: true,
1266
1590
  warnings: [],
1267
1591
  };
1268
1592
  try {
1269
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1270
- throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1593
+ const newSpecs = yield this.getFilteredSpecs(filter, signal);
1594
+ const newUnResolvedSpec = newSpecs[0];
1595
+ const newSpec = newSpecs[1];
1596
+ let resultStr;
1597
+ if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1598
+ resultStr = jsyaml__default['default'].dump(newUnResolvedSpec);
1271
1599
  }
1272
- yield this.loadSpec();
1273
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1274
- throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1600
+ else {
1601
+ resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1275
1602
  }
1276
- const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1603
+ yield fs__default['default'].outputFile(outputSpecPath, resultStr);
1277
1604
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1278
1605
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1279
1606
  }
1280
- const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
1281
- const AuthSet = new Set();
1282
- let hasMultipleAPIKeyAuth = false;
1607
+ const [updatedManifest, apiPlugin] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
1608
+ yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1609
+ yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
1610
+ }
1611
+ catch (err) {
1612
+ if (err instanceof SpecParserError) {
1613
+ throw err;
1614
+ }
1615
+ throw new SpecParserError(err.toString(), exports.ErrorType.GenerateFailed);
1616
+ }
1617
+ return result;
1618
+ });
1619
+ }
1620
+ /**
1621
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1622
+ * @param manifestPath A file path of the Teams app manifest file to update.
1623
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1624
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1625
+ * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1626
+ */
1627
+ generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1628
+ return __awaiter(this, void 0, void 0, function* () {
1629
+ const result = {
1630
+ allSuccess: true,
1631
+ warnings: [],
1632
+ };
1633
+ try {
1634
+ const newSpecs = yield this.getFilteredSpecs(filter, signal);
1635
+ const newUnResolvedSpec = newSpecs[0];
1636
+ const newSpec = newSpecs[1];
1637
+ let hasMultipleAuth = false;
1638
+ let authInfo = undefined;
1283
1639
  for (const url in newSpec.paths) {
1284
1640
  for (const method in newSpec.paths[url]) {
1285
1641
  const operation = newSpec.paths[url][method];
1286
1642
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1287
1643
  if (authArray && authArray.length > 0) {
1288
- AuthSet.add(authArray[0][0].authSchema);
1289
- if (AuthSet.size > 1) {
1290
- hasMultipleAPIKeyAuth = true;
1644
+ const currentAuth = authArray[0][0];
1645
+ if (!authInfo) {
1646
+ authInfo = authArray[0][0];
1647
+ }
1648
+ else if (authInfo.name !== currentAuth.name) {
1649
+ hasMultipleAuth = true;
1291
1650
  break;
1292
1651
  }
1293
1652
  }
1294
1653
  }
1295
1654
  }
1296
- if (hasMultipleAPIKeyAuth) {
1297
- throw new SpecParserError(ConstantString.MultipleAPIKeyNotSupported, exports.ErrorType.MultipleAPIKeyNotSupported);
1655
+ if (hasMultipleAuth && this.options.projectType !== exports.ProjectType.TeamsAi) {
1656
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, exports.ErrorType.MultipleAuthNotSupported);
1298
1657
  }
1299
1658
  let resultStr;
1300
1659
  if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
@@ -1304,26 +1663,28 @@ class SpecParser {
1304
1663
  resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1305
1664
  }
1306
1665
  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
- });
1666
+ if (adaptiveCardFolder) {
1667
+ for (const url in newSpec.paths) {
1668
+ for (const method in newSpec.paths[url]) {
1669
+ // paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
1670
+ if (this.options.allowMethods.includes(method)) {
1671
+ const operation = newSpec.paths[url][method];
1672
+ try {
1673
+ const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1674
+ const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
1675
+ const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1676
+ yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
1677
+ const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1678
+ yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
1679
+ }
1680
+ catch (err) {
1681
+ result.allSuccess = false;
1682
+ result.warnings.push({
1683
+ type: exports.WarningType.GenerateCardFailed,
1684
+ content: err.toString(),
1685
+ data: operation.operationId,
1686
+ });
1687
+ }
1327
1688
  }
1328
1689
  }
1329
1690
  }
@@ -1331,8 +1692,7 @@ class SpecParser {
1331
1692
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1332
1693
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1333
1694
  }
1334
- const auth = Array.from(AuthSet)[0];
1335
- const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth);
1695
+ const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1336
1696
  yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1337
1697
  result.warnings.push(...warnings);
1338
1698
  }
@@ -1360,16 +1720,17 @@ class SpecParser {
1360
1720
  }
1361
1721
  });
1362
1722
  }
1363
- getAllSupportedAPIs(spec) {
1723
+ getAPIs(spec) {
1364
1724
  if (this.apiMap !== undefined) {
1365
1725
  return this.apiMap;
1366
1726
  }
1367
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1727
+ const result = Utils.listAPIs(spec, this.options);
1368
1728
  this.apiMap = result;
1369
1729
  return result;
1370
1730
  }
1371
1731
  }
1372
1732
 
1733
+ exports.AdaptiveCardGenerator = AdaptiveCardGenerator;
1373
1734
  exports.ConstantString = ConstantString;
1374
1735
  exports.SpecParser = SpecParser;
1375
1736
  exports.SpecParserError = SpecParserError;