@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.
@@ -19,7 +19,8 @@ var ErrorType;
19
19
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
20
20
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
21
21
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
22
- ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
22
+ ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
23
+ ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
23
24
  ErrorType["ListFailed"] = "list-failed";
24
25
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
25
26
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -27,6 +28,22 @@ var ErrorType;
27
28
  ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
28
29
  ErrorType["GenerateFailed"] = "generate-failed";
29
30
  ErrorType["ValidateFailed"] = "validate-failed";
31
+ ErrorType["GetSpecFailed"] = "get-spec-failed";
32
+ ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
33
+ ErrorType["MissingOperationId"] = "missing-operation-id";
34
+ ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
35
+ ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
36
+ ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
37
+ ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
38
+ ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
39
+ ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
40
+ ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
41
+ ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
42
+ ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
43
+ ErrorType["NoParameter"] = "no-parameter";
44
+ ErrorType["NoAPIInfo"] = "no-api-info";
45
+ ErrorType["MethodNotAllowed"] = "method-not-allowed";
46
+ ErrorType["UrlPathNotExist"] = "url-path-not-exist";
30
47
  ErrorType["Cancelled"] = "cancelled";
31
48
  ErrorType["Unknown"] = "unknown";
32
49
  })(ErrorType || (ErrorType = {}));
@@ -49,7 +66,13 @@ var ValidationStatus;
49
66
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
50
67
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
51
68
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
52
- })(ValidationStatus || (ValidationStatus = {}));
69
+ })(ValidationStatus || (ValidationStatus = {}));
70
+ var ProjectType;
71
+ (function (ProjectType) {
72
+ ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
73
+ ProjectType[ProjectType["SME"] = 1] = "SME";
74
+ ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
75
+ })(ProjectType || (ProjectType = {}));
53
76
 
54
77
  // Copyright (c) Microsoft Corporation.
55
78
  class ConstantString {
@@ -68,7 +91,9 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
68
91
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
69
92
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
70
93
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
71
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
94
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
95
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
96
+ ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
72
97
  ConstantString.WrappedCardVersion = "devPreview";
73
98
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
74
99
  ConstantString.WrappedCardResponseLayout = "list";
@@ -80,6 +105,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
80
105
  ConstantString.TextBlockType = "TextBlock";
81
106
  ConstantString.ContainerType = "Container";
82
107
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
108
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
83
109
  ConstantString.ResponseCodeFor20X = [
84
110
  "200",
85
111
  "201",
@@ -139,7 +165,8 @@ ConstantString.FullDescriptionMaxLens = 4000;
139
165
  ConstantString.CommandDescriptionMaxLens = 128;
140
166
  ConstantString.ParameterDescriptionMaxLens = 128;
141
167
  ConstantString.CommandTitleMaxLens = 32;
142
- ConstantString.ParameterTitleMaxLens = 32;
168
+ ConstantString.ParameterTitleMaxLens = 32;
169
+ ConstantString.SMERequiredParamsMaxNum = 5;
143
170
 
144
171
  // Copyright (c) Microsoft Corporation.
145
172
  class SpecParserError extends Error {
@@ -151,11 +178,23 @@ class SpecParserError extends Error {
151
178
 
152
179
  // Copyright (c) Microsoft Corporation.
153
180
  class Utils {
154
- static checkParameters(paramObject) {
181
+ static hasNestedObjectInSchema(schema) {
182
+ if (schema.type === "object") {
183
+ for (const property in schema.properties) {
184
+ const nestedSchema = schema.properties[property];
185
+ if (nestedSchema.type === "object") {
186
+ return true;
187
+ }
188
+ }
189
+ }
190
+ return false;
191
+ }
192
+ static checkParameters(paramObject, isCopilot) {
155
193
  const paramResult = {
156
194
  requiredNum: 0,
157
195
  optionalNum: 0,
158
196
  isValid: true,
197
+ reason: [],
159
198
  };
160
199
  if (!paramObject) {
161
200
  return paramResult;
@@ -163,10 +202,25 @@ class Utils {
163
202
  for (let i = 0; i < paramObject.length; i++) {
164
203
  const param = paramObject[i];
165
204
  const schema = param.schema;
205
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
206
+ paramResult.isValid = false;
207
+ paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
208
+ continue;
209
+ }
166
210
  const isRequiredWithoutDefault = param.required && schema.default === undefined;
211
+ if (isCopilot) {
212
+ if (isRequiredWithoutDefault) {
213
+ paramResult.requiredNum = paramResult.requiredNum + 1;
214
+ }
215
+ else {
216
+ paramResult.optionalNum = paramResult.optionalNum + 1;
217
+ }
218
+ continue;
219
+ }
167
220
  if (param.in === "header" || param.in === "cookie") {
168
221
  if (isRequiredWithoutDefault) {
169
222
  paramResult.isValid = false;
223
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
170
224
  }
171
225
  continue;
172
226
  }
@@ -176,6 +230,7 @@ class Utils {
176
230
  schema.type !== "integer") {
177
231
  if (isRequiredWithoutDefault) {
178
232
  paramResult.isValid = false;
233
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
179
234
  }
180
235
  continue;
181
236
  }
@@ -190,17 +245,23 @@ class Utils {
190
245
  }
191
246
  return paramResult;
192
247
  }
193
- static checkPostBody(schema, isRequired = false) {
248
+ static checkPostBody(schema, isRequired = false, isCopilot = false) {
194
249
  var _a;
195
250
  const paramResult = {
196
251
  requiredNum: 0,
197
252
  optionalNum: 0,
198
253
  isValid: true,
254
+ reason: [],
199
255
  };
200
256
  if (Object.keys(schema).length === 0) {
201
257
  return paramResult;
202
258
  }
203
259
  const isRequiredWithoutDefault = isRequired && schema.default === undefined;
260
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
261
+ paramResult.isValid = false;
262
+ paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
263
+ return paramResult;
264
+ }
204
265
  if (schema.type === "string" ||
205
266
  schema.type === "integer" ||
206
267
  schema.type === "boolean" ||
@@ -219,19 +280,24 @@ class Utils {
219
280
  if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
220
281
  isRequired = true;
221
282
  }
222
- const result = Utils.checkPostBody(properties[property], isRequired);
283
+ const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
223
284
  paramResult.requiredNum += result.requiredNum;
224
285
  paramResult.optionalNum += result.optionalNum;
225
286
  paramResult.isValid = paramResult.isValid && result.isValid;
287
+ paramResult.reason.push(...result.reason);
226
288
  }
227
289
  }
228
290
  else {
229
- if (isRequiredWithoutDefault) {
291
+ if (isRequiredWithoutDefault && !isCopilot) {
230
292
  paramResult.isValid = false;
293
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
231
294
  }
232
295
  }
233
296
  return paramResult;
234
297
  }
298
+ static containMultipleMediaTypes(bodyObject) {
299
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
300
+ }
235
301
  /**
236
302
  * Checks if the given API is supported.
237
303
  * @param {string} method - The HTTP method of the API.
@@ -246,106 +312,137 @@ class Utils {
246
312
  * 5. response body should be “application/json” and not empty, and response code should be 20X
247
313
  * 6. only support request body with “application/json” content type
248
314
  */
249
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
250
- const pathObj = spec.paths[path];
315
+ static isSupportedApi(method, path, spec, options) {
316
+ var _a;
317
+ const result = { isValid: true, reason: [] };
251
318
  method = method.toLocaleLowerCase();
252
- if (pathObj) {
253
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
254
- pathObj[method]) {
255
- const securities = pathObj[method].security;
256
- const authArray = Utils.getAuthArray(securities, spec);
257
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
258
- return false;
259
- }
260
- const operationObject = pathObj[method];
261
- if (!allowMissingId && !operationObject.operationId) {
262
- return false;
263
- }
264
- const paramObject = operationObject.parameters;
265
- const requestBody = operationObject.requestBody;
266
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
267
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
268
- if (mediaTypesCount > 1) {
269
- return false;
270
- }
271
- const responseJson = Utils.getResponseJson(operationObject);
272
- if (Object.keys(responseJson).length === 0) {
273
- return false;
274
- }
275
- let requestBodyParamResult = {
276
- requiredNum: 0,
277
- optionalNum: 0,
278
- isValid: true,
279
- };
280
- if (requestJsonBody) {
281
- const requestBodySchema = requestJsonBody.schema;
282
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
283
- }
284
- if (!requestBodyParamResult.isValid) {
285
- return false;
319
+ if (options.allowMethods && !options.allowMethods.includes(method)) {
320
+ result.isValid = false;
321
+ result.reason.push(ErrorType.MethodNotAllowed);
322
+ return result;
323
+ }
324
+ const pathObj = spec.paths[path];
325
+ if (!pathObj || !pathObj[method]) {
326
+ result.isValid = false;
327
+ result.reason.push(ErrorType.UrlPathNotExist);
328
+ return result;
329
+ }
330
+ const securities = pathObj[method].security;
331
+ const isTeamsAi = options.projectType === ProjectType.TeamsAi;
332
+ const isCopilot = options.projectType === ProjectType.Copilot;
333
+ // Teams AI project doesn't care about auth, it will use authProvider for user to implement
334
+ if (!isTeamsAi) {
335
+ const authArray = Utils.getAuthArray(securities, spec);
336
+ const authCheckResult = Utils.isSupportedAuth(authArray, options);
337
+ if (!authCheckResult.isValid) {
338
+ result.reason.push(...authCheckResult.reason);
339
+ }
340
+ }
341
+ const operationObject = pathObj[method];
342
+ if (!options.allowMissingId && !operationObject.operationId) {
343
+ result.reason.push(ErrorType.MissingOperationId);
344
+ }
345
+ const rootServer = spec.servers && spec.servers[0];
346
+ const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
347
+ const operationServer = operationObject.servers && operationObject.servers[0];
348
+ const serverUrl = operationServer || methodServer || rootServer;
349
+ if (!serverUrl) {
350
+ result.reason.push(ErrorType.NoServerInformation);
351
+ }
352
+ else {
353
+ const serverValidateResult = Utils.checkServerUrl([serverUrl]);
354
+ result.reason.push(...serverValidateResult.map((item) => item.type));
355
+ }
356
+ const paramObject = operationObject.parameters;
357
+ const requestBody = operationObject.requestBody;
358
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
359
+ if (!isTeamsAi && Utils.containMultipleMediaTypes(requestBody)) {
360
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
361
+ }
362
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject, isTeamsAi);
363
+ if (multipleMediaType && !isTeamsAi) {
364
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
365
+ }
366
+ else if (Object.keys(json).length === 0) {
367
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
368
+ }
369
+ // Teams AI project doesn't care about request parameters/body
370
+ if (!isTeamsAi) {
371
+ let requestBodyParamResult = {
372
+ requiredNum: 0,
373
+ optionalNum: 0,
374
+ isValid: true,
375
+ reason: [],
376
+ };
377
+ if (requestJsonBody) {
378
+ const requestBodySchema = requestJsonBody.schema;
379
+ if (isCopilot && requestBodySchema.type !== "object") {
380
+ result.reason.push(ErrorType.PostBodySchemaIsNotJson);
286
381
  }
287
- const paramResult = Utils.checkParameters(paramObject);
288
- if (!paramResult.isValid) {
289
- return false;
382
+ requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
383
+ if (!requestBodyParamResult.isValid && requestBodyParamResult.reason) {
384
+ result.reason.push(...requestBodyParamResult.reason);
290
385
  }
291
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
292
- if (allowMultipleParameters &&
293
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
294
- return true;
386
+ }
387
+ const paramResult = Utils.checkParameters(paramObject, isCopilot);
388
+ if (!paramResult.isValid && paramResult.reason) {
389
+ result.reason.push(...paramResult.reason);
390
+ }
391
+ // Copilot support arbitrary parameters
392
+ if (!isCopilot && paramResult.isValid && requestBodyParamResult.isValid) {
393
+ const totalRequiredParams = requestBodyParamResult.requiredNum + paramResult.requiredNum;
394
+ const totalParams = totalRequiredParams + requestBodyParamResult.optionalNum + paramResult.optionalNum;
395
+ if (totalRequiredParams > 1) {
396
+ if (!options.allowMultipleParameters ||
397
+ totalRequiredParams > ConstantString.SMERequiredParamsMaxNum) {
398
+ result.reason.push(ErrorType.ExceededRequiredParamsLimit);
295
399
  }
296
- return false;
297
- }
298
- else if (requestBodyParamResult.requiredNum +
299
- requestBodyParamResult.optionalNum +
300
- paramResult.requiredNum +
301
- paramResult.optionalNum ===
302
- 0) {
303
- return false;
304
400
  }
305
- else {
306
- return true;
401
+ else if (totalParams === 0) {
402
+ result.reason.push(ErrorType.NoParameter);
307
403
  }
308
404
  }
309
405
  }
310
- return false;
406
+ if (result.reason.length > 0) {
407
+ result.isValid = false;
408
+ }
409
+ return result;
311
410
  }
312
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
313
- if (authSchemaArray.length === 0) {
314
- return true;
411
+ static isSupportedAuth(authSchemeArray, options) {
412
+ if (authSchemeArray.length === 0) {
413
+ return { isValid: true, reason: [] };
315
414
  }
316
- if (allowAPIKeyAuth || allowOauth2) {
415
+ if (options.allowAPIKeyAuth || options.allowOauth2 || options.allowBearerTokenAuth) {
317
416
  // Currently we don't support multiple auth in one operation
318
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
319
- return false;
417
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
418
+ return {
419
+ isValid: false,
420
+ reason: [ErrorType.MultipleAuthNotSupported],
421
+ };
320
422
  }
321
- for (const auths of authSchemaArray) {
423
+ for (const auths of authSchemeArray) {
322
424
  if (auths.length === 1) {
323
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
324
- return true;
325
- }
326
- else if (!allowAPIKeyAuth &&
327
- allowOauth2 &&
328
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
329
- return true;
330
- }
331
- else if (allowAPIKeyAuth &&
332
- allowOauth2 &&
333
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
334
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
335
- return true;
425
+ if ((options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
426
+ (options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
427
+ (options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
428
+ return { isValid: true, reason: [] };
336
429
  }
337
430
  }
338
431
  }
339
432
  }
340
- return false;
433
+ return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
341
434
  }
342
- static isAPIKeyAuth(authSchema) {
343
- return authSchema.type === "apiKey";
435
+ static isBearerTokenAuth(authScheme) {
436
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
344
437
  }
345
- static isBearerTokenAuth(authSchema) {
346
- return (authSchema.type === "oauth2" ||
347
- authSchema.type === "openIdConnect" ||
348
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
438
+ static isAPIKeyAuth(authScheme) {
439
+ return authScheme.type === "apiKey";
440
+ }
441
+ static isOAuthWithAuthCodeFlow(authScheme) {
442
+ if (authScheme.type === "oauth2" && authScheme.flows && authScheme.flows.authorizationCode) {
443
+ return true;
444
+ }
445
+ return false;
349
446
  }
350
447
  static getAuthArray(securities, spec) {
351
448
  var _a;
@@ -358,7 +455,7 @@ class Utils {
358
455
  for (const name in security) {
359
456
  const auth = securitySchemas[name];
360
457
  authArray.push({
361
- authSchema: auth,
458
+ authScheme: auth,
362
459
  name: name,
363
460
  });
364
461
  }
@@ -373,21 +470,28 @@ class Utils {
373
470
  static updateFirstLetter(str) {
374
471
  return str.charAt(0).toUpperCase() + str.slice(1);
375
472
  }
376
- static getResponseJson(operationObject) {
473
+ static getResponseJson(operationObject, isTeamsAiProject = false) {
377
474
  var _a, _b;
378
475
  let json = {};
476
+ let multipleMediaType = false;
379
477
  for (const code of ConstantString.ResponseCodeFor20X) {
380
478
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
381
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
382
- if (mediaTypesCount > 1) {
383
- return {};
384
- }
385
479
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
480
+ multipleMediaType = false;
386
481
  json = responseObject.content["application/json"];
387
- break;
482
+ if (Utils.containMultipleMediaTypes(responseObject)) {
483
+ multipleMediaType = true;
484
+ if (isTeamsAiProject) {
485
+ break;
486
+ }
487
+ json = {};
488
+ }
489
+ else {
490
+ break;
491
+ }
388
492
  }
389
493
  }
390
- return json;
494
+ return { json, multipleMediaType };
391
495
  }
392
496
  static convertPathToCamelCase(path) {
393
497
  const pathSegments = path.split(/[./{]/);
@@ -407,10 +511,10 @@ class Utils {
407
511
  return undefined;
408
512
  }
409
513
  }
410
- static resolveServerUrl(url) {
514
+ static resolveEnv(str) {
411
515
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
412
- let matches = placeHolderReg.exec(url);
413
- let newUrl = url;
516
+ let matches = placeHolderReg.exec(str);
517
+ let newStr = str;
414
518
  while (matches != null) {
415
519
  const envVar = matches[1];
416
520
  const envVal = process.env[envVar];
@@ -418,17 +522,17 @@ class Utils {
418
522
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
419
523
  }
420
524
  else {
421
- newUrl = newUrl.replace(matches[0], envVal);
525
+ newStr = newStr.replace(matches[0], envVal);
422
526
  }
423
- matches = placeHolderReg.exec(url);
527
+ matches = placeHolderReg.exec(str);
424
528
  }
425
- return newUrl;
529
+ return newStr;
426
530
  }
427
531
  static checkServerUrl(servers) {
428
532
  const errors = [];
429
533
  let serverUrl;
430
534
  try {
431
- serverUrl = Utils.resolveServerUrl(servers[0].url);
535
+ serverUrl = Utils.resolveEnv(servers[0].url);
432
536
  }
433
537
  catch (err) {
434
538
  errors.push({
@@ -458,7 +562,8 @@ class Utils {
458
562
  }
459
563
  return errors;
460
564
  }
461
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
565
+ static validateServer(spec, options) {
566
+ var _a;
462
567
  const errors = [];
463
568
  let hasTopLevelServers = false;
464
569
  let hasPathLevelServers = false;
@@ -479,7 +584,7 @@ class Utils {
479
584
  }
480
585
  for (const method in methods) {
481
586
  const operationObject = methods[method];
482
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
587
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
483
588
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
484
589
  hasOperationLevelServers = true;
485
590
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -522,6 +627,7 @@ class Utils {
522
627
  Utils.updateParameterWithInputType(schema, parameter);
523
628
  }
524
629
  if (isRequired && schema.default === undefined) {
630
+ parameter.isRequired = true;
525
631
  requiredParams.push(parameter);
526
632
  }
527
633
  else {
@@ -566,7 +672,7 @@ class Utils {
566
672
  param.value = schema.default;
567
673
  }
568
674
  }
569
- static parseApiInfo(operationItem, allowMultipleParameters) {
675
+ static parseApiInfo(operationItem, options) {
570
676
  var _a, _b;
571
677
  const requiredParams = [];
572
678
  const optionalParams = [];
@@ -580,11 +686,12 @@ class Utils {
580
686
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
581
687
  };
582
688
  const schema = param.schema;
583
- if (allowMultipleParameters && schema) {
689
+ if (options.allowMultipleParameters && schema) {
584
690
  Utils.updateParameterWithInputType(schema, parameter);
585
691
  }
586
692
  if (param.in !== "header" && param.in !== "cookie") {
587
693
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
694
+ parameter.isRequired = true;
588
695
  requiredParams.push(parameter);
589
696
  }
590
697
  else {
@@ -598,7 +705,7 @@ class Utils {
598
705
  const requestJson = requestBody.content["application/json"];
599
706
  if (Object.keys(requestJson).length !== 0) {
600
707
  const schema = requestJson.schema;
601
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
708
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
602
709
  requiredParams.push(...requiredP);
603
710
  optionalParams.push(...optionalP);
604
711
  }
@@ -629,32 +736,37 @@ class Utils {
629
736
  }
630
737
  return [command, warning];
631
738
  }
632
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
739
+ static listAPIs(spec, options) {
740
+ var _a;
633
741
  const paths = spec.paths;
634
742
  const result = {};
635
743
  for (const path in paths) {
636
744
  const methods = paths[path];
637
745
  for (const method in methods) {
638
- // For developer preview, only support GET operation with only 1 parameter without auth
639
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
640
- const operationObject = methods[method];
641
- result[`${method.toUpperCase()} ${path}`] = operationObject;
746
+ const operationObject = methods[method];
747
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
748
+ const validateResult = Utils.isSupportedApi(method, path, spec, options);
749
+ result[`${method.toUpperCase()} ${path}`] = {
750
+ operation: operationObject,
751
+ isValid: validateResult.isValid,
752
+ reason: validateResult.reason,
753
+ };
642
754
  }
643
755
  }
644
756
  }
645
757
  return result;
646
758
  }
647
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
759
+ static validateSpec(spec, parser, isSwaggerFile, options) {
648
760
  const errors = [];
649
761
  const warnings = [];
762
+ const apiMap = Utils.listAPIs(spec, options);
650
763
  if (isSwaggerFile) {
651
764
  warnings.push({
652
765
  type: WarningType.ConvertSwaggerToOpenAPI,
653
766
  content: ConstantString.ConvertSwaggerToOpenAPI,
654
767
  });
655
768
  }
656
- // Server validation
657
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
769
+ const serverErrors = Utils.validateServer(spec, options);
658
770
  errors.push(...serverErrors);
659
771
  // Remote reference not supported
660
772
  const refPaths = parser.$refs.paths();
@@ -667,8 +779,8 @@ class Utils {
667
779
  });
668
780
  }
669
781
  // No supported API
670
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
671
- if (Object.keys(apiMap).length === 0) {
782
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
783
+ if (validAPIs.length === 0) {
672
784
  errors.push({
673
785
  type: ErrorType.NoSupportedApi,
674
786
  content: ConstantString.NoSupportedApi,
@@ -677,8 +789,8 @@ class Utils {
677
789
  // OperationId missing
678
790
  const apisMissingOperationId = [];
679
791
  for (const key in apiMap) {
680
- const pathObjectItem = apiMap[key];
681
- if (!pathObjectItem.operationId) {
792
+ const { operation } = apiMap[key];
793
+ if (!operation.operationId) {
682
794
  apisMissingOperationId.push(key);
683
795
  }
684
796
  }
@@ -719,30 +831,50 @@ class Utils {
719
831
  }
720
832
  return safeRegistrationIdEnvName;
721
833
  }
834
+ static getAllAPICount(spec) {
835
+ let count = 0;
836
+ const paths = spec.paths;
837
+ for (const path in paths) {
838
+ const methods = paths[path];
839
+ for (const method in methods) {
840
+ if (ConstantString.AllOperationMethods.includes(method)) {
841
+ count++;
842
+ }
843
+ }
844
+ }
845
+ return count;
846
+ }
722
847
  }
723
848
 
724
849
  // Copyright (c) Microsoft Corporation.
725
850
  class SpecFilter {
726
- static specFilter(filter, unResolveSpec, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
851
+ static specFilter(filter, unResolveSpec, resolvedSpec, options) {
852
+ var _a;
727
853
  try {
728
854
  const newSpec = Object.assign({}, unResolveSpec);
729
855
  const newPaths = {};
730
856
  for (const filterItem of filter) {
731
857
  const [method, path] = filterItem.split(" ");
732
858
  const methodName = method.toLowerCase();
733
- if (!Utils.isSupportedApi(methodName, path, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
734
- continue;
735
- }
736
- if (!newPaths[path]) {
737
- newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
738
- for (const m of ConstantString.AllOperationMethods) {
739
- delete newPaths[path][m];
859
+ const pathObj = (_a = resolvedSpec.paths) === null || _a === void 0 ? void 0 : _a[path];
860
+ if (ConstantString.AllOperationMethods.includes(methodName) &&
861
+ pathObj &&
862
+ pathObj[methodName]) {
863
+ const validateResult = Utils.isSupportedApi(methodName, path, resolvedSpec, options);
864
+ if (!validateResult.isValid) {
865
+ continue;
866
+ }
867
+ if (!newPaths[path]) {
868
+ newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
869
+ for (const m of ConstantString.AllOperationMethods) {
870
+ delete newPaths[path][m];
871
+ }
872
+ }
873
+ newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
874
+ // Add the operationId if missing
875
+ if (!newPaths[path][methodName].operationId) {
876
+ newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
740
877
  }
741
- }
742
- newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
743
- // Add the operationId if missing
744
- if (!newPaths[path][methodName].operationId) {
745
- newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
746
878
  }
747
879
  }
748
880
  newSpec.paths = newPaths;
@@ -756,46 +888,168 @@ class SpecFilter {
756
888
 
757
889
  // Copyright (c) Microsoft Corporation.
758
890
  class ManifestUpdater {
759
- static async updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, spec, allowMultipleParameters, auth) {
891
+ static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
892
+ const manifest = await fs.readJSON(manifestPath);
893
+ const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
894
+ manifest.plugins = [
895
+ {
896
+ pluginFile: apiPluginRelativePath,
897
+ },
898
+ ];
899
+ const appName = this.removeEnvs(manifest.name.short);
900
+ ManifestUpdater.updateManifestDescription(manifest, spec);
901
+ const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
902
+ const apiPlugin = ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, appName, options);
903
+ return [manifest, apiPlugin];
904
+ }
905
+ static updateManifestDescription(manifest, spec) {
760
906
  var _a, _b;
907
+ manifest.description = {
908
+ short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
909
+ 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),
910
+ };
911
+ }
912
+ static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
913
+ let parameter;
914
+ if (schema.type === "string" ||
915
+ schema.type === "boolean" ||
916
+ schema.type === "integer" ||
917
+ schema.type === "number" ||
918
+ schema.type === "array") {
919
+ parameter = schema;
920
+ }
921
+ else {
922
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
923
+ }
924
+ return parameter;
925
+ }
926
+ static generatePluginManifestSchema(spec, specRelativePath, appName, options) {
927
+ var _a, _b, _c;
928
+ const functions = [];
929
+ const functionNames = [];
930
+ const paths = spec.paths;
931
+ for (const pathUrl in paths) {
932
+ const pathItem = paths[pathUrl];
933
+ if (pathItem) {
934
+ const operations = pathItem;
935
+ for (const method in operations) {
936
+ if (options.allowMethods.includes(method)) {
937
+ const operationItem = operations[method];
938
+ if (operationItem) {
939
+ const operationId = operationItem.operationId;
940
+ const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
941
+ const paramObject = operationItem.parameters;
942
+ const requestBody = operationItem.requestBody;
943
+ const parameters = {
944
+ type: "object",
945
+ properties: {},
946
+ required: [],
947
+ };
948
+ if (paramObject) {
949
+ for (let i = 0; i < paramObject.length; i++) {
950
+ const param = paramObject[i];
951
+ const schema = param.schema;
952
+ parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
953
+ if (param.required) {
954
+ parameters.required.push(param.name);
955
+ }
956
+ if (!parameters.properties[param.name].description) {
957
+ parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
958
+ }
959
+ }
960
+ }
961
+ if (requestBody) {
962
+ const requestJsonBody = requestBody.content["application/json"];
963
+ const requestBodySchema = requestJsonBody.schema;
964
+ if (requestBodySchema.type === "object") {
965
+ if (requestBodySchema.required) {
966
+ parameters.required.push(...requestBodySchema.required);
967
+ }
968
+ for (const property in requestBodySchema.properties) {
969
+ const schema = requestBodySchema.properties[property];
970
+ parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
971
+ }
972
+ }
973
+ else {
974
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
975
+ }
976
+ }
977
+ const funcObj = {
978
+ name: operationId,
979
+ description: description,
980
+ parameters: parameters,
981
+ };
982
+ functions.push(funcObj);
983
+ functionNames.push(operationId);
984
+ }
985
+ }
986
+ }
987
+ }
988
+ }
989
+ const apiPlugin = {
990
+ schema_version: "v2",
991
+ name_for_human: appName,
992
+ description_for_human: (_c = spec.info.description) !== null && _c !== void 0 ? _c : "<Please add description of the plugin>",
993
+ functions: functions,
994
+ runtimes: [
995
+ {
996
+ type: "OpenApi",
997
+ auth: {
998
+ type: "none", // TODO, support auth in the future
999
+ },
1000
+ spec: {
1001
+ url: specRelativePath,
1002
+ },
1003
+ run_for_functions: functionNames,
1004
+ },
1005
+ ],
1006
+ };
1007
+ return apiPlugin;
1008
+ }
1009
+ static async updateManifest(manifestPath, outputSpecPath, spec, options, adaptiveCardFolder, authInfo) {
761
1010
  try {
762
1011
  const originalManifest = await fs.readJSON(manifestPath);
763
1012
  const updatedPart = {};
764
- const [commands, warnings] = await ManifestUpdater.generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters);
765
- const composeExtension = {
766
- composeExtensionType: "apiBased",
767
- apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
768
- commands: commands,
769
- };
770
- if (auth) {
771
- if (Utils.isAPIKeyAuth(auth)) {
772
- auth = auth;
773
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${auth.name}_${ConstantString.RegistrationIdPostfix}`);
774
- composeExtension.authorization = {
775
- authType: "apiSecretServiceAuth",
776
- apiSecretServiceAuthConfiguration: {
777
- apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
778
- },
779
- };
780
- }
781
- else if (Utils.isBearerTokenAuth(auth)) {
782
- composeExtension.authorization = {
783
- authType: "microsoftEntra",
784
- microsoftEntraConfiguration: {
785
- supportsSingleSignOn: true,
786
- },
787
- };
788
- updatedPart.webApplicationInfo = {
789
- id: "${{AAD_APP_CLIENT_ID}}",
790
- resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
791
- };
1013
+ updatedPart.composeExtensions = [];
1014
+ let warnings = [];
1015
+ if (options.projectType === ProjectType.SME) {
1016
+ const updateResult = await ManifestUpdater.generateCommands(spec, manifestPath, options, adaptiveCardFolder);
1017
+ const commands = updateResult[0];
1018
+ warnings = updateResult[1];
1019
+ const composeExtension = {
1020
+ composeExtensionType: "apiBased",
1021
+ apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
1022
+ commands: commands,
1023
+ };
1024
+ if (authInfo) {
1025
+ const auth = authInfo.authScheme;
1026
+ if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1027
+ const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
1028
+ composeExtension.authorization = {
1029
+ authType: "apiSecretServiceAuth",
1030
+ apiSecretServiceAuthConfiguration: {
1031
+ apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
1032
+ },
1033
+ };
1034
+ }
1035
+ else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
1036
+ const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
1037
+ composeExtension.authorization = {
1038
+ authType: "oAuth2.0",
1039
+ oAuthConfiguration: {
1040
+ oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
1041
+ },
1042
+ };
1043
+ updatedPart.webApplicationInfo = {
1044
+ id: "${{AAD_APP_CLIENT_ID}}",
1045
+ resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
1046
+ };
1047
+ }
792
1048
  }
1049
+ updatedPart.composeExtensions = [composeExtension];
793
1050
  }
794
- updatedPart.description = {
795
- short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
796
- 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),
797
- };
798
- updatedPart.composeExtensions = [composeExtension];
1051
+ updatedPart.description = originalManifest.description;
1052
+ ManifestUpdater.updateManifestDescription(updatedPart, spec);
799
1053
  const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
800
1054
  return [updatedManifest, warnings];
801
1055
  }
@@ -803,7 +1057,8 @@ class ManifestUpdater {
803
1057
  throw new SpecParserError(err.toString(), ErrorType.UpdateManifestFailed);
804
1058
  }
805
1059
  }
806
- static async generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters) {
1060
+ static async generateCommands(spec, manifestPath, options, adaptiveCardFolder) {
1061
+ var _a;
807
1062
  const paths = spec.paths;
808
1063
  const commands = [];
809
1064
  const warnings = [];
@@ -814,14 +1069,16 @@ class ManifestUpdater {
814
1069
  const operations = pathItem;
815
1070
  // Currently only support GET and POST method
816
1071
  for (const method in operations) {
817
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1072
+ if ((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) {
818
1073
  const operationItem = operations[method];
819
1074
  if (operationItem) {
820
- const [command, warning] = Utils.parseApiInfo(operationItem, allowMultipleParameters);
821
- const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
822
- command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
823
- ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
824
- : "";
1075
+ const [command, warning] = Utils.parseApiInfo(operationItem, options);
1076
+ if (adaptiveCardFolder) {
1077
+ const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
1078
+ command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
1079
+ ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
1080
+ : "";
1081
+ }
825
1082
  if (warning) {
826
1083
  warnings.push(warning);
827
1084
  }
@@ -838,13 +1095,22 @@ class ManifestUpdater {
838
1095
  const relativePath = path.relative(path.dirname(from), to);
839
1096
  return path.normalize(relativePath).replace(/\\/g, "/");
840
1097
  }
1098
+ static removeEnvs(str) {
1099
+ const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
1100
+ const matches = placeHolderReg.exec(str);
1101
+ let newStr = str;
1102
+ if (matches != null) {
1103
+ newStr = newStr.replace(matches[0], "");
1104
+ }
1105
+ return newStr;
1106
+ }
841
1107
  }
842
1108
 
843
1109
  // Copyright (c) Microsoft Corporation.
844
1110
  class AdaptiveCardGenerator {
845
1111
  static generateAdaptiveCard(operationItem) {
846
1112
  try {
847
- const json = Utils.getResponseJson(operationItem);
1113
+ const { json } = Utils.getResponseJson(operationItem);
848
1114
  let cardBody = [];
849
1115
  let schema = json.schema;
850
1116
  let jsonPath = "$";
@@ -1104,8 +1370,11 @@ class SpecParser {
1104
1370
  allowMissingId: true,
1105
1371
  allowSwagger: true,
1106
1372
  allowAPIKeyAuth: false,
1373
+ allowBearerTokenAuth: false,
1107
1374
  allowMultipleParameters: false,
1108
1375
  allowOauth2: false,
1376
+ allowMethods: ["get", "post"],
1377
+ projectType: ProjectType.SME,
1109
1378
  };
1110
1379
  this.pathOrSpec = pathOrDoc;
1111
1380
  this.parser = new SwaggerParser();
@@ -1138,7 +1407,23 @@ class SpecParser {
1138
1407
  ],
1139
1408
  };
1140
1409
  }
1141
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1410
+ if (this.options.projectType === ProjectType.SME ||
1411
+ this.options.projectType === ProjectType.Copilot) {
1412
+ if (this.spec.openapi >= "3.1.0") {
1413
+ return {
1414
+ status: ValidationStatus.Error,
1415
+ warnings: [],
1416
+ errors: [
1417
+ {
1418
+ type: ErrorType.SpecVersionNotSupported,
1419
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
1420
+ data: this.spec.openapi,
1421
+ },
1422
+ ],
1423
+ };
1424
+ }
1425
+ }
1426
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
1142
1427
  }
1143
1428
  catch (err) {
1144
1429
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -1158,16 +1443,22 @@ class SpecParser {
1158
1443
  try {
1159
1444
  await this.loadSpec();
1160
1445
  const spec = this.spec;
1161
- const apiMap = this.getAllSupportedAPIs(spec);
1162
- const result = [];
1446
+ const apiMap = this.getAPIs(spec);
1447
+ const result = {
1448
+ APIs: [],
1449
+ allAPICount: 0,
1450
+ validAPICount: 0,
1451
+ };
1163
1452
  for (const apiKey in apiMap) {
1453
+ const { operation, isValid, reason } = apiMap[apiKey];
1454
+ const [method, path] = apiKey.split(" ");
1164
1455
  const apiResult = {
1165
1456
  api: "",
1166
1457
  server: "",
1167
1458
  operationId: "",
1459
+ isValid: isValid,
1460
+ reason: reason,
1168
1461
  };
1169
- const [method, path] = apiKey.split(" ");
1170
- const operation = apiMap[apiKey];
1171
1462
  const rootServer = spec.servers && spec.servers[0];
1172
1463
  const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
1173
1464
  const operationServer = operation.servers && operation.servers[0];
@@ -1175,7 +1466,7 @@ class SpecParser {
1175
1466
  if (!serverUrl) {
1176
1467
  throw new SpecParserError(ConstantString.NoServerInformation, ErrorType.NoServerInformation);
1177
1468
  }
1178
- apiResult.server = Utils.resolveServerUrl(serverUrl.url);
1469
+ apiResult.server = Utils.resolveEnv(serverUrl.url);
1179
1470
  let operationId = operation.operationId;
1180
1471
  if (!operationId) {
1181
1472
  operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
@@ -1184,13 +1475,15 @@ class SpecParser {
1184
1475
  const authArray = Utils.getAuthArray(operation.security, spec);
1185
1476
  for (const auths of authArray) {
1186
1477
  if (auths.length === 1) {
1187
- apiResult.auth = auths[0].authSchema;
1478
+ apiResult.auth = auths[0];
1188
1479
  break;
1189
1480
  }
1190
1481
  }
1191
1482
  apiResult.api = apiKey;
1192
- result.push(apiResult);
1483
+ result.APIs.push(apiResult);
1193
1484
  }
1485
+ result.allAPICount = result.APIs.length;
1486
+ result.validAPICount = result.APIs.filter((api) => api.isValid).length;
1194
1487
  return result;
1195
1488
  }
1196
1489
  catch (err) {
@@ -1200,48 +1493,108 @@ class SpecParser {
1200
1493
  throw new SpecParserError(err.toString(), ErrorType.ListFailed);
1201
1494
  }
1202
1495
  }
1496
+ /**
1497
+ * Generate specs according to the filters.
1498
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1499
+ */
1500
+ async getFilteredSpecs(filter, signal) {
1501
+ try {
1502
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1503
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1504
+ }
1505
+ await this.loadSpec();
1506
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1507
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1508
+ }
1509
+ const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options);
1510
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1511
+ throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1512
+ }
1513
+ const newSpec = (await this.parser.dereference(newUnResolvedSpec));
1514
+ return [newUnResolvedSpec, newSpec];
1515
+ }
1516
+ catch (err) {
1517
+ if (err instanceof SpecParserError) {
1518
+ throw err;
1519
+ }
1520
+ throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
1521
+ }
1522
+ }
1203
1523
  /**
1204
1524
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1205
1525
  * @param manifestPath A file path of the Teams app manifest file to update.
1206
1526
  * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1207
1527
  * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1208
- * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1528
+ * @param pluginFilePath File path of the api plugin file to generate.
1209
1529
  */
1210
- async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1530
+ async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1211
1531
  const result = {
1212
1532
  allSuccess: true,
1213
1533
  warnings: [],
1214
1534
  };
1215
1535
  try {
1216
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1217
- throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1536
+ const newSpecs = await this.getFilteredSpecs(filter, signal);
1537
+ const newUnResolvedSpec = newSpecs[0];
1538
+ const newSpec = newSpecs[1];
1539
+ let resultStr;
1540
+ if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1541
+ resultStr = jsyaml.dump(newUnResolvedSpec);
1218
1542
  }
1219
- await this.loadSpec();
1220
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1221
- throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1543
+ else {
1544
+ resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1222
1545
  }
1223
- const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1546
+ await fs.outputFile(outputSpecPath, resultStr);
1224
1547
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1225
1548
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1226
1549
  }
1227
- const newSpec = (await this.parser.dereference(newUnResolvedSpec));
1228
- const AuthSet = new Set();
1229
- let hasMultipleAPIKeyAuth = false;
1550
+ const [updatedManifest, apiPlugin] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
1551
+ await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1552
+ await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
1553
+ }
1554
+ catch (err) {
1555
+ if (err instanceof SpecParserError) {
1556
+ throw err;
1557
+ }
1558
+ throw new SpecParserError(err.toString(), ErrorType.GenerateFailed);
1559
+ }
1560
+ return result;
1561
+ }
1562
+ /**
1563
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1564
+ * @param manifestPath A file path of the Teams app manifest file to update.
1565
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1566
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1567
+ * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1568
+ */
1569
+ async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1570
+ const result = {
1571
+ allSuccess: true,
1572
+ warnings: [],
1573
+ };
1574
+ try {
1575
+ const newSpecs = await this.getFilteredSpecs(filter, signal);
1576
+ const newUnResolvedSpec = newSpecs[0];
1577
+ const newSpec = newSpecs[1];
1578
+ let hasMultipleAuth = false;
1579
+ let authInfo = undefined;
1230
1580
  for (const url in newSpec.paths) {
1231
1581
  for (const method in newSpec.paths[url]) {
1232
1582
  const operation = newSpec.paths[url][method];
1233
1583
  const authArray = Utils.getAuthArray(operation.security, newSpec);
1234
1584
  if (authArray && authArray.length > 0) {
1235
- AuthSet.add(authArray[0][0].authSchema);
1236
- if (AuthSet.size > 1) {
1237
- hasMultipleAPIKeyAuth = true;
1585
+ const currentAuth = authArray[0][0];
1586
+ if (!authInfo) {
1587
+ authInfo = authArray[0][0];
1588
+ }
1589
+ else if (authInfo.name !== currentAuth.name) {
1590
+ hasMultipleAuth = true;
1238
1591
  break;
1239
1592
  }
1240
1593
  }
1241
1594
  }
1242
1595
  }
1243
- if (hasMultipleAPIKeyAuth) {
1244
- throw new SpecParserError(ConstantString.MultipleAPIKeyNotSupported, ErrorType.MultipleAPIKeyNotSupported);
1596
+ if (hasMultipleAuth && this.options.projectType !== ProjectType.TeamsAi) {
1597
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
1245
1598
  }
1246
1599
  let resultStr;
1247
1600
  if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
@@ -1251,26 +1604,28 @@ class SpecParser {
1251
1604
  resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1252
1605
  }
1253
1606
  await fs.outputFile(outputSpecPath, resultStr);
1254
- for (const url in newSpec.paths) {
1255
- for (const method in newSpec.paths[url]) {
1256
- // paths object may contain description/summary, so we need to check if it is a operation object
1257
- if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1258
- const operation = newSpec.paths[url][method];
1259
- try {
1260
- const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1261
- const fileName = path.join(adaptiveCardFolder, `${operation.operationId}.json`);
1262
- const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1263
- await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
1264
- const dataFileName = path.join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1265
- await fs.outputJSON(dataFileName, {}, { spaces: 2 });
1266
- }
1267
- catch (err) {
1268
- result.allSuccess = false;
1269
- result.warnings.push({
1270
- type: WarningType.GenerateCardFailed,
1271
- content: err.toString(),
1272
- data: operation.operationId,
1273
- });
1607
+ if (adaptiveCardFolder) {
1608
+ for (const url in newSpec.paths) {
1609
+ for (const method in newSpec.paths[url]) {
1610
+ // paths object may contain description/summary which is not a http method, so we need to check if it is a operation object
1611
+ if (this.options.allowMethods.includes(method)) {
1612
+ const operation = newSpec.paths[url][method];
1613
+ try {
1614
+ const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1615
+ const fileName = path.join(adaptiveCardFolder, `${operation.operationId}.json`);
1616
+ const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1617
+ await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
1618
+ const dataFileName = path.join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1619
+ await fs.outputJSON(dataFileName, {}, { spaces: 2 });
1620
+ }
1621
+ catch (err) {
1622
+ result.allSuccess = false;
1623
+ result.warnings.push({
1624
+ type: WarningType.GenerateCardFailed,
1625
+ content: err.toString(),
1626
+ data: operation.operationId,
1627
+ });
1628
+ }
1274
1629
  }
1275
1630
  }
1276
1631
  }
@@ -1278,8 +1633,7 @@ class SpecParser {
1278
1633
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1279
1634
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1280
1635
  }
1281
- const auth = Array.from(AuthSet)[0];
1282
- const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth);
1636
+ const [updatedManifest, warnings] = await ManifestUpdater.updateManifest(manifestPath, outputSpecPath, newSpec, this.options, adaptiveCardFolder, authInfo);
1283
1637
  await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1284
1638
  result.warnings.push(...warnings);
1285
1639
  }
@@ -1304,15 +1658,15 @@ class SpecParser {
1304
1658
  this.spec = (await this.parser.dereference(clonedUnResolveSpec));
1305
1659
  }
1306
1660
  }
1307
- getAllSupportedAPIs(spec) {
1661
+ getAPIs(spec) {
1308
1662
  if (this.apiMap !== undefined) {
1309
1663
  return this.apiMap;
1310
1664
  }
1311
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1665
+ const result = Utils.listAPIs(spec, this.options);
1312
1666
  this.apiMap = result;
1313
1667
  return result;
1314
1668
  }
1315
1669
  }
1316
1670
 
1317
- export { ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
1671
+ export { AdaptiveCardGenerator, ConstantString, ErrorType, ProjectType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
1318
1672
  //# sourceMappingURL=index.esm2017.mjs.map