@microsoft/m365-spec-parser 0.1.1-alpha.48b9eab36.0 → 0.1.1-alpha.4e708f092.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.
@@ -15,7 +15,8 @@ var ErrorType;
15
15
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
16
16
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
17
17
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
18
- ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
18
+ ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
19
+ ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
19
20
  ErrorType["ListFailed"] = "list-failed";
20
21
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
21
22
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -24,6 +25,21 @@ var ErrorType;
24
25
  ErrorType["GenerateFailed"] = "generate-failed";
25
26
  ErrorType["ValidateFailed"] = "validate-failed";
26
27
  ErrorType["GetSpecFailed"] = "get-spec-failed";
28
+ ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
29
+ ErrorType["MissingOperationId"] = "missing-operation-id";
30
+ ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
31
+ ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
32
+ ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
33
+ ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
34
+ ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
35
+ ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
36
+ ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
37
+ ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
38
+ ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
39
+ ErrorType["NoParameter"] = "no-parameter";
40
+ ErrorType["NoAPIInfo"] = "no-api-info";
41
+ ErrorType["MethodNotAllowed"] = "method-not-allowed";
42
+ ErrorType["UrlPathNotExist"] = "url-path-not-exist";
27
43
  ErrorType["Cancelled"] = "cancelled";
28
44
  ErrorType["Unknown"] = "unknown";
29
45
  })(ErrorType || (ErrorType = {}));
@@ -46,7 +62,13 @@ var ValidationStatus;
46
62
  ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
47
63
  ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
48
64
  ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
49
- })(ValidationStatus || (ValidationStatus = {}));
65
+ })(ValidationStatus || (ValidationStatus = {}));
66
+ var ProjectType;
67
+ (function (ProjectType) {
68
+ ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
69
+ ProjectType[ProjectType["SME"] = 1] = "SME";
70
+ ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
71
+ })(ProjectType || (ProjectType = {}));
50
72
 
51
73
  // Copyright (c) Microsoft Corporation.
52
74
  class SpecParserError extends Error {
@@ -73,7 +95,9 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
73
95
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
74
96
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
75
97
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
76
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
98
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
99
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
100
+ ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
77
101
  ConstantString.WrappedCardVersion = "devPreview";
78
102
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
79
103
  ConstantString.WrappedCardResponseLayout = "list";
@@ -83,8 +107,10 @@ ConstantString.AdaptiveCardVersion = "1.5";
83
107
  ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
84
108
  ConstantString.AdaptiveCardType = "AdaptiveCard";
85
109
  ConstantString.TextBlockType = "TextBlock";
110
+ ConstantString.ImageType = "Image";
86
111
  ConstantString.ContainerType = "Container";
87
112
  ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
113
+ ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
88
114
  ConstantString.ResponseCodeFor20X = [
89
115
  "200",
90
116
  "201",
@@ -144,205 +170,36 @@ ConstantString.FullDescriptionMaxLens = 4000;
144
170
  ConstantString.CommandDescriptionMaxLens = 128;
145
171
  ConstantString.ParameterDescriptionMaxLens = 128;
146
172
  ConstantString.CommandTitleMaxLens = 32;
147
- ConstantString.ParameterTitleMaxLens = 32;
173
+ ConstantString.ParameterTitleMaxLens = 32;
174
+ ConstantString.SMERequiredParamsMaxNum = 5;
175
+ ConstantString.DefaultPluginId = "plugin_1";
148
176
 
149
177
  // Copyright (c) Microsoft Corporation.
150
178
  class Utils {
151
- static checkParameters(paramObject) {
152
- const paramResult = {
153
- requiredNum: 0,
154
- optionalNum: 0,
155
- isValid: true,
156
- };
157
- if (!paramObject) {
158
- return paramResult;
159
- }
160
- for (let i = 0; i < paramObject.length; i++) {
161
- const param = paramObject[i];
162
- const schema = param.schema;
163
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
164
- if (param.in === "header" || param.in === "cookie") {
165
- if (isRequiredWithoutDefault) {
166
- paramResult.isValid = false;
167
- }
168
- continue;
169
- }
170
- if (schema.type !== "boolean" &&
171
- schema.type !== "string" &&
172
- schema.type !== "number" &&
173
- schema.type !== "integer") {
174
- if (isRequiredWithoutDefault) {
175
- paramResult.isValid = false;
176
- }
177
- continue;
178
- }
179
- if (param.in === "query" || param.in === "path") {
180
- if (isRequiredWithoutDefault) {
181
- paramResult.requiredNum = paramResult.requiredNum + 1;
182
- }
183
- else {
184
- paramResult.optionalNum = paramResult.optionalNum + 1;
185
- }
186
- }
187
- }
188
- return paramResult;
189
- }
190
- static checkPostBody(schema, isRequired = false) {
191
- var _a;
192
- const paramResult = {
193
- requiredNum: 0,
194
- optionalNum: 0,
195
- isValid: true,
196
- };
197
- if (Object.keys(schema).length === 0) {
198
- return paramResult;
199
- }
200
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
201
- if (schema.type === "string" ||
202
- schema.type === "integer" ||
203
- schema.type === "boolean" ||
204
- schema.type === "number") {
205
- if (isRequiredWithoutDefault) {
206
- paramResult.requiredNum = paramResult.requiredNum + 1;
207
- }
208
- else {
209
- paramResult.optionalNum = paramResult.optionalNum + 1;
210
- }
211
- }
212
- else if (schema.type === "object") {
213
- const { properties } = schema;
214
- for (const property in properties) {
215
- let isRequired = false;
216
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
217
- isRequired = true;
218
- }
219
- const result = Utils.checkPostBody(properties[property], isRequired);
220
- paramResult.requiredNum += result.requiredNum;
221
- paramResult.optionalNum += result.optionalNum;
222
- paramResult.isValid = paramResult.isValid && result.isValid;
223
- }
224
- }
225
- else {
226
- if (isRequiredWithoutDefault) {
227
- paramResult.isValid = false;
228
- }
229
- }
230
- return paramResult;
231
- }
232
- /**
233
- * Checks if the given API is supported.
234
- * @param {string} method - The HTTP method of the API.
235
- * @param {string} path - The path of the API.
236
- * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
237
- * @returns {boolean} - Returns true if the API is supported, false otherwise.
238
- * @description The following APIs are supported:
239
- * 1. only support Get/Post operation without auth property
240
- * 2. parameter inside query or path only support string, number, boolean and integer
241
- * 3. parameter inside post body only support string, number, boolean, integer and object
242
- * 4. request body + required parameters <= 1
243
- * 5. response body should be “application/json” and not empty, and response code should be 20X
244
- * 6. only support request body with “application/json” content type
245
- */
246
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
247
- const pathObj = spec.paths[path];
248
- method = method.toLocaleLowerCase();
249
- if (pathObj) {
250
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
251
- pathObj[method]) {
252
- const securities = pathObj[method].security;
253
- const authArray = Utils.getAuthArray(securities, spec);
254
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
255
- return false;
256
- }
257
- const operationObject = pathObj[method];
258
- if (!allowMissingId && !operationObject.operationId) {
259
- return false;
260
- }
261
- const paramObject = operationObject.parameters;
262
- const requestBody = operationObject.requestBody;
263
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
264
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
265
- if (mediaTypesCount > 1) {
266
- return false;
267
- }
268
- const responseJson = Utils.getResponseJson(operationObject);
269
- if (Object.keys(responseJson).length === 0) {
270
- return false;
271
- }
272
- let requestBodyParamResult = {
273
- requiredNum: 0,
274
- optionalNum: 0,
275
- isValid: true,
276
- };
277
- if (requestJsonBody) {
278
- const requestBodySchema = requestJsonBody.schema;
279
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
280
- }
281
- if (!requestBodyParamResult.isValid) {
282
- return false;
283
- }
284
- const paramResult = Utils.checkParameters(paramObject);
285
- if (!paramResult.isValid) {
286
- return false;
287
- }
288
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
289
- if (allowMultipleParameters &&
290
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
291
- return true;
292
- }
293
- return false;
294
- }
295
- else if (requestBodyParamResult.requiredNum +
296
- requestBodyParamResult.optionalNum +
297
- paramResult.requiredNum +
298
- paramResult.optionalNum ===
299
- 0) {
300
- return false;
301
- }
302
- else {
179
+ static hasNestedObjectInSchema(schema) {
180
+ if (schema.type === "object") {
181
+ for (const property in schema.properties) {
182
+ const nestedSchema = schema.properties[property];
183
+ if (nestedSchema.type === "object") {
303
184
  return true;
304
185
  }
305
186
  }
306
187
  }
307
188
  return false;
308
189
  }
309
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
310
- if (authSchemaArray.length === 0) {
311
- return true;
312
- }
313
- if (allowAPIKeyAuth || allowOauth2) {
314
- // Currently we don't support multiple auth in one operation
315
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
316
- return false;
317
- }
318
- for (const auths of authSchemaArray) {
319
- if (auths.length === 1) {
320
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
321
- return true;
322
- }
323
- else if (!allowAPIKeyAuth &&
324
- allowOauth2 &&
325
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
326
- return true;
327
- }
328
- else if (allowAPIKeyAuth &&
329
- allowOauth2 &&
330
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
331
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
332
- return true;
333
- }
334
- }
335
- }
336
- }
337
- return false;
190
+ static containMultipleMediaTypes(bodyObject) {
191
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
192
+ }
193
+ static isBearerTokenAuth(authScheme) {
194
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
338
195
  }
339
- static isAPIKeyAuth(authSchema) {
340
- return authSchema.type === "apiKey";
196
+ static isAPIKeyAuth(authScheme) {
197
+ return authScheme.type === "apiKey";
341
198
  }
342
- static isBearerTokenAuth(authSchema) {
343
- return (authSchema.type === "oauth2" ||
344
- authSchema.type === "openIdConnect" ||
345
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
199
+ static isOAuthWithAuthCodeFlow(authScheme) {
200
+ return !!(authScheme.type === "oauth2" &&
201
+ authScheme.flows &&
202
+ authScheme.flows.authorizationCode);
346
203
  }
347
204
  static getAuthArray(securities, spec) {
348
205
  var _a;
@@ -355,7 +212,7 @@ class Utils {
355
212
  for (const name in security) {
356
213
  const auth = securitySchemas[name];
357
214
  authArray.push({
358
- authSchema: auth,
215
+ authScheme: auth,
359
216
  name: name,
360
217
  });
361
218
  }
@@ -373,18 +230,22 @@ class Utils {
373
230
  static getResponseJson(operationObject) {
374
231
  var _a, _b;
375
232
  let json = {};
233
+ let multipleMediaType = false;
376
234
  for (const code of ConstantString.ResponseCodeFor20X) {
377
235
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
378
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
379
- if (mediaTypesCount > 1) {
380
- return {};
381
- }
382
236
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
237
+ multipleMediaType = false;
383
238
  json = responseObject.content["application/json"];
384
- break;
239
+ if (Utils.containMultipleMediaTypes(responseObject)) {
240
+ multipleMediaType = true;
241
+ json = {};
242
+ }
243
+ else {
244
+ break;
245
+ }
385
246
  }
386
247
  }
387
- return json;
248
+ return { json, multipleMediaType };
388
249
  }
389
250
  static convertPathToCamelCase(path) {
390
251
  const pathSegments = path.split(/[./{]/);
@@ -404,10 +265,10 @@ class Utils {
404
265
  return undefined;
405
266
  }
406
267
  }
407
- static resolveServerUrl(url) {
268
+ static resolveEnv(str) {
408
269
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
409
- let matches = placeHolderReg.exec(url);
410
- let newUrl = url;
270
+ let matches = placeHolderReg.exec(str);
271
+ let newStr = str;
411
272
  while (matches != null) {
412
273
  const envVar = matches[1];
413
274
  const envVal = process.env[envVar];
@@ -415,17 +276,17 @@ class Utils {
415
276
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
416
277
  }
417
278
  else {
418
- newUrl = newUrl.replace(matches[0], envVal);
279
+ newStr = newStr.replace(matches[0], envVal);
419
280
  }
420
- matches = placeHolderReg.exec(url);
281
+ matches = placeHolderReg.exec(str);
421
282
  }
422
- return newUrl;
283
+ return newStr;
423
284
  }
424
285
  static checkServerUrl(servers) {
425
286
  const errors = [];
426
287
  let serverUrl;
427
288
  try {
428
- serverUrl = Utils.resolveServerUrl(servers[0].url);
289
+ serverUrl = Utils.resolveEnv(servers[0].url);
429
290
  }
430
291
  catch (err) {
431
292
  errors.push({
@@ -455,7 +316,8 @@ class Utils {
455
316
  }
456
317
  return errors;
457
318
  }
458
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
319
+ static validateServer(spec, options) {
320
+ var _a;
459
321
  const errors = [];
460
322
  let hasTopLevelServers = false;
461
323
  let hasPathLevelServers = false;
@@ -476,7 +338,7 @@ class Utils {
476
338
  }
477
339
  for (const method in methods) {
478
340
  const operationObject = methods[method];
479
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
341
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
480
342
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
481
343
  hasOperationLevelServers = true;
482
344
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -519,6 +381,7 @@ class Utils {
519
381
  Utils.updateParameterWithInputType(schema, parameter);
520
382
  }
521
383
  if (isRequired && schema.default === undefined) {
384
+ parameter.isRequired = true;
522
385
  requiredParams.push(parameter);
523
386
  }
524
387
  else {
@@ -563,7 +426,7 @@ class Utils {
563
426
  param.value = schema.default;
564
427
  }
565
428
  }
566
- static parseApiInfo(operationItem, allowMultipleParameters) {
429
+ static parseApiInfo(operationItem, options) {
567
430
  var _a, _b;
568
431
  const requiredParams = [];
569
432
  const optionalParams = [];
@@ -577,11 +440,12 @@ class Utils {
577
440
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
578
441
  };
579
442
  const schema = param.schema;
580
- if (allowMultipleParameters && schema) {
443
+ if (options.allowMultipleParameters && schema) {
581
444
  Utils.updateParameterWithInputType(schema, parameter);
582
445
  }
583
446
  if (param.in !== "header" && param.in !== "cookie") {
584
447
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
448
+ parameter.isRequired = true;
585
449
  requiredParams.push(parameter);
586
450
  }
587
451
  else {
@@ -595,19 +459,13 @@ class Utils {
595
459
  const requestJson = requestBody.content["application/json"];
596
460
  if (Object.keys(requestJson).length !== 0) {
597
461
  const schema = requestJson.schema;
598
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
462
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
599
463
  requiredParams.push(...requiredP);
600
464
  optionalParams.push(...optionalP);
601
465
  }
602
466
  }
603
467
  const operationId = operationItem.operationId;
604
- const parameters = [];
605
- if (requiredParams.length !== 0) {
606
- parameters.push(...requiredParams);
607
- }
608
- else {
609
- parameters.push(optionalParams[0]);
610
- }
468
+ const parameters = [...requiredParams, ...optionalParams];
611
469
  const command = {
612
470
  context: ["compose"],
613
471
  type: "query",
@@ -616,105 +474,535 @@ class Utils {
616
474
  parameters: parameters,
617
475
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
618
476
  };
619
- let warning = undefined;
620
- if (requiredParams.length === 0 && optionalParams.length > 1) {
621
- warning = {
622
- type: WarningType.OperationOnlyContainsOptionalParam,
623
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
624
- data: operationId,
625
- };
477
+ return command;
478
+ }
479
+ static format(str, ...args) {
480
+ let index = 0;
481
+ return str.replace(/%s/g, () => {
482
+ const arg = args[index++];
483
+ return arg !== undefined ? arg : "";
484
+ });
485
+ }
486
+ static getSafeRegistrationIdEnvName(authName) {
487
+ if (!authName) {
488
+ return "";
626
489
  }
627
- return [command, warning];
490
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
491
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
492
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
493
+ }
494
+ return safeRegistrationIdEnvName;
628
495
  }
629
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
630
- const paths = spec.paths;
496
+ static getServerObject(spec, method, path) {
497
+ const pathObj = spec.paths[path];
498
+ const operationObject = pathObj[method];
499
+ const rootServer = spec.servers && spec.servers[0];
500
+ const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
501
+ const operationServer = operationObject.servers && operationObject.servers[0];
502
+ const serverUrl = operationServer || methodServer || rootServer;
503
+ return serverUrl;
504
+ }
505
+ }
506
+
507
+ // Copyright (c) Microsoft Corporation.
508
+ class Validator {
509
+ listAPIs() {
510
+ var _a;
511
+ if (this.apiMap) {
512
+ return this.apiMap;
513
+ }
514
+ const paths = this.spec.paths;
631
515
  const result = {};
632
516
  for (const path in paths) {
633
517
  const methods = paths[path];
634
518
  for (const method in methods) {
635
- // For developer preview, only support GET operation with only 1 parameter without auth
636
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
637
- const operationObject = methods[method];
638
- result[`${method.toUpperCase()} ${path}`] = operationObject;
519
+ const operationObject = methods[method];
520
+ if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
521
+ const validateResult = this.validateAPI(method, path);
522
+ result[`${method.toUpperCase()} ${path}`] = {
523
+ operation: operationObject,
524
+ isValid: validateResult.isValid,
525
+ reason: validateResult.reason,
526
+ };
639
527
  }
640
528
  }
641
529
  }
530
+ this.apiMap = result;
642
531
  return result;
643
532
  }
644
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
645
- const errors = [];
646
- const warnings = [];
647
- if (isSwaggerFile) {
648
- warnings.push({
649
- type: WarningType.ConvertSwaggerToOpenAPI,
650
- content: ConstantString.ConvertSwaggerToOpenAPI,
651
- });
652
- }
653
- // Server validation
654
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
655
- errors.push(...serverErrors);
656
- // Remote reference not supported
657
- const refPaths = parser.$refs.paths();
658
- // refPaths [0] is the current spec file path
659
- if (refPaths.length > 1) {
660
- errors.push({
661
- type: ErrorType.RemoteRefNotSupported,
662
- content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
663
- data: refPaths,
533
+ validateSpecVersion() {
534
+ const result = { errors: [], warnings: [] };
535
+ if (this.spec.openapi >= "3.1.0") {
536
+ result.errors.push({
537
+ type: ErrorType.SpecVersionNotSupported,
538
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
539
+ data: this.spec.openapi,
664
540
  });
665
541
  }
666
- // No supported API
667
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
668
- if (Object.keys(apiMap).length === 0) {
669
- errors.push({
542
+ return result;
543
+ }
544
+ validateSpecServer() {
545
+ const result = { errors: [], warnings: [] };
546
+ const serverErrors = Utils.validateServer(this.spec, this.options);
547
+ result.errors.push(...serverErrors);
548
+ return result;
549
+ }
550
+ validateSpecNoSupportAPI() {
551
+ const result = { errors: [], warnings: [] };
552
+ const apiMap = this.listAPIs();
553
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
554
+ if (validAPIs.length === 0) {
555
+ const data = [];
556
+ for (const key in apiMap) {
557
+ const { reason } = apiMap[key];
558
+ const apiInvalidReason = { api: key, reason: reason };
559
+ data.push(apiInvalidReason);
560
+ }
561
+ result.errors.push({
670
562
  type: ErrorType.NoSupportedApi,
671
563
  content: ConstantString.NoSupportedApi,
564
+ data,
672
565
  });
673
566
  }
567
+ return result;
568
+ }
569
+ validateSpecOperationId() {
570
+ const result = { errors: [], warnings: [] };
571
+ const apiMap = this.listAPIs();
674
572
  // OperationId missing
675
573
  const apisMissingOperationId = [];
676
574
  for (const key in apiMap) {
677
- const pathObjectItem = apiMap[key];
678
- if (!pathObjectItem.operationId) {
575
+ const { operation } = apiMap[key];
576
+ if (!operation.operationId) {
679
577
  apisMissingOperationId.push(key);
680
578
  }
681
579
  }
682
580
  if (apisMissingOperationId.length > 0) {
683
- warnings.push({
581
+ result.warnings.push({
684
582
  type: WarningType.OperationIdMissing,
685
583
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
686
584
  data: apisMissingOperationId,
687
585
  });
688
586
  }
689
- let status = ValidationStatus.Valid;
690
- if (warnings.length > 0 && errors.length === 0) {
691
- status = ValidationStatus.Warning;
587
+ return result;
588
+ }
589
+ validateMethodAndPath(method, path) {
590
+ const result = { isValid: true, reason: [] };
591
+ if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
592
+ result.isValid = false;
593
+ result.reason.push(ErrorType.MethodNotAllowed);
594
+ return result;
595
+ }
596
+ const pathObj = this.spec.paths[path];
597
+ if (!pathObj || !pathObj[method]) {
598
+ result.isValid = false;
599
+ result.reason.push(ErrorType.UrlPathNotExist);
600
+ return result;
601
+ }
602
+ return result;
603
+ }
604
+ validateResponse(method, path) {
605
+ const result = { isValid: true, reason: [] };
606
+ const operationObject = this.spec.paths[path][method];
607
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
608
+ // only support response body only contains “application/json” content type
609
+ if (multipleMediaType) {
610
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
611
+ }
612
+ else if (Object.keys(json).length === 0) {
613
+ // response body should not be empty
614
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
615
+ }
616
+ return result;
617
+ }
618
+ validateServer(method, path) {
619
+ const result = { isValid: true, reason: [] };
620
+ const serverObj = Utils.getServerObject(this.spec, method, path);
621
+ if (!serverObj) {
622
+ // should contain server URL
623
+ result.reason.push(ErrorType.NoServerInformation);
624
+ }
625
+ else {
626
+ // server url should be absolute url with https protocol
627
+ const serverValidateResult = Utils.checkServerUrl([serverObj]);
628
+ result.reason.push(...serverValidateResult.map((item) => item.type));
629
+ }
630
+ return result;
631
+ }
632
+ validateAuth(method, path) {
633
+ const pathObj = this.spec.paths[path];
634
+ const operationObject = pathObj[method];
635
+ const securities = operationObject.security;
636
+ const authSchemeArray = Utils.getAuthArray(securities, this.spec);
637
+ if (authSchemeArray.length === 0) {
638
+ return { isValid: true, reason: [] };
639
+ }
640
+ if (this.options.allowAPIKeyAuth ||
641
+ this.options.allowOauth2 ||
642
+ this.options.allowBearerTokenAuth) {
643
+ // Currently we don't support multiple auth in one operation
644
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
645
+ return {
646
+ isValid: false,
647
+ reason: [ErrorType.MultipleAuthNotSupported],
648
+ };
649
+ }
650
+ for (const auths of authSchemeArray) {
651
+ if (auths.length === 1) {
652
+ if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
653
+ (this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
654
+ (this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
655
+ return { isValid: true, reason: [] };
656
+ }
657
+ }
658
+ }
659
+ }
660
+ return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
661
+ }
662
+ checkPostBodySchema(schema, isRequired = false) {
663
+ var _a;
664
+ const paramResult = {
665
+ requiredNum: 0,
666
+ optionalNum: 0,
667
+ isValid: true,
668
+ reason: [],
669
+ };
670
+ if (Object.keys(schema).length === 0) {
671
+ return paramResult;
672
+ }
673
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
674
+ const isCopilot = this.projectType === ProjectType.Copilot;
675
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
676
+ paramResult.isValid = false;
677
+ paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
678
+ return paramResult;
679
+ }
680
+ if (schema.type === "string" ||
681
+ schema.type === "integer" ||
682
+ schema.type === "boolean" ||
683
+ schema.type === "number") {
684
+ if (isRequiredWithoutDefault) {
685
+ paramResult.requiredNum = paramResult.requiredNum + 1;
686
+ }
687
+ else {
688
+ paramResult.optionalNum = paramResult.optionalNum + 1;
689
+ }
690
+ }
691
+ else if (schema.type === "object") {
692
+ const { properties } = schema;
693
+ for (const property in properties) {
694
+ let isRequired = false;
695
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
696
+ isRequired = true;
697
+ }
698
+ const result = this.checkPostBodySchema(properties[property], isRequired);
699
+ paramResult.requiredNum += result.requiredNum;
700
+ paramResult.optionalNum += result.optionalNum;
701
+ paramResult.isValid = paramResult.isValid && result.isValid;
702
+ paramResult.reason.push(...result.reason);
703
+ }
692
704
  }
693
- else if (errors.length > 0) {
694
- status = ValidationStatus.Error;
705
+ else {
706
+ if (isRequiredWithoutDefault && !isCopilot) {
707
+ paramResult.isValid = false;
708
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
709
+ }
695
710
  }
696
- return {
697
- status,
698
- warnings,
699
- errors,
711
+ return paramResult;
712
+ }
713
+ checkParamSchema(paramObject) {
714
+ const paramResult = {
715
+ requiredNum: 0,
716
+ optionalNum: 0,
717
+ isValid: true,
718
+ reason: [],
700
719
  };
720
+ if (!paramObject) {
721
+ return paramResult;
722
+ }
723
+ const isCopilot = this.projectType === ProjectType.Copilot;
724
+ for (let i = 0; i < paramObject.length; i++) {
725
+ const param = paramObject[i];
726
+ const schema = param.schema;
727
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
728
+ paramResult.isValid = false;
729
+ paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
730
+ continue;
731
+ }
732
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
733
+ if (isCopilot) {
734
+ if (isRequiredWithoutDefault) {
735
+ paramResult.requiredNum = paramResult.requiredNum + 1;
736
+ }
737
+ else {
738
+ paramResult.optionalNum = paramResult.optionalNum + 1;
739
+ }
740
+ continue;
741
+ }
742
+ if (param.in === "header" || param.in === "cookie") {
743
+ if (isRequiredWithoutDefault) {
744
+ paramResult.isValid = false;
745
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
746
+ }
747
+ continue;
748
+ }
749
+ if (schema.type !== "boolean" &&
750
+ schema.type !== "string" &&
751
+ schema.type !== "number" &&
752
+ schema.type !== "integer") {
753
+ if (isRequiredWithoutDefault) {
754
+ paramResult.isValid = false;
755
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
756
+ }
757
+ continue;
758
+ }
759
+ if (param.in === "query" || param.in === "path") {
760
+ if (isRequiredWithoutDefault) {
761
+ paramResult.requiredNum = paramResult.requiredNum + 1;
762
+ }
763
+ else {
764
+ paramResult.optionalNum = paramResult.optionalNum + 1;
765
+ }
766
+ }
767
+ }
768
+ return paramResult;
701
769
  }
702
- static format(str, ...args) {
703
- let index = 0;
704
- return str.replace(/%s/g, () => {
705
- const arg = args[index++];
706
- return arg !== undefined ? arg : "";
707
- });
770
+ hasNestedObjectInSchema(schema) {
771
+ if (schema.type === "object") {
772
+ for (const property in schema.properties) {
773
+ const nestedSchema = schema.properties[property];
774
+ if (nestedSchema.type === "object") {
775
+ return true;
776
+ }
777
+ }
778
+ }
779
+ return false;
708
780
  }
709
- static getSafeRegistrationIdEnvName(authName) {
710
- if (!authName) {
711
- return "";
781
+ }
782
+
783
+ // Copyright (c) Microsoft Corporation.
784
+ class CopilotValidator extends Validator {
785
+ constructor(spec, options) {
786
+ super();
787
+ this.projectType = ProjectType.Copilot;
788
+ this.options = options;
789
+ this.spec = spec;
790
+ }
791
+ validateSpec() {
792
+ const result = { errors: [], warnings: [] };
793
+ // validate spec version
794
+ let validationResult = this.validateSpecVersion();
795
+ result.errors.push(...validationResult.errors);
796
+ // validate spec server
797
+ validationResult = this.validateSpecServer();
798
+ result.errors.push(...validationResult.errors);
799
+ // validate no supported API
800
+ validationResult = this.validateSpecNoSupportAPI();
801
+ result.errors.push(...validationResult.errors);
802
+ // validate operationId missing
803
+ validationResult = this.validateSpecOperationId();
804
+ result.warnings.push(...validationResult.warnings);
805
+ return result;
806
+ }
807
+ validateAPI(method, path) {
808
+ const result = { isValid: true, reason: [] };
809
+ method = method.toLocaleLowerCase();
810
+ // validate method and path
811
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
812
+ if (!methodAndPathResult.isValid) {
813
+ return methodAndPathResult;
712
814
  }
713
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
714
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
715
- safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
815
+ const operationObject = this.spec.paths[path][method];
816
+ // validate auth
817
+ const authCheckResult = this.validateAuth(method, path);
818
+ result.reason.push(...authCheckResult.reason);
819
+ // validate operationId
820
+ if (!this.options.allowMissingId && !operationObject.operationId) {
821
+ result.reason.push(ErrorType.MissingOperationId);
822
+ }
823
+ // validate server
824
+ const validateServerResult = this.validateServer(method, path);
825
+ result.reason.push(...validateServerResult.reason);
826
+ // validate response
827
+ const validateResponseResult = this.validateResponse(method, path);
828
+ result.reason.push(...validateResponseResult.reason);
829
+ // validate requestBody
830
+ const requestBody = operationObject.requestBody;
831
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
832
+ if (Utils.containMultipleMediaTypes(requestBody)) {
833
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
834
+ }
835
+ if (requestJsonBody) {
836
+ const requestBodySchema = requestJsonBody.schema;
837
+ if (requestBodySchema.type !== "object") {
838
+ result.reason.push(ErrorType.PostBodySchemaIsNotJson);
839
+ }
840
+ const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
841
+ result.reason.push(...requestBodyParamResult.reason);
842
+ }
843
+ // validate parameters
844
+ const paramObject = operationObject.parameters;
845
+ const paramResult = this.checkParamSchema(paramObject);
846
+ result.reason.push(...paramResult.reason);
847
+ if (result.reason.length > 0) {
848
+ result.isValid = false;
849
+ }
850
+ return result;
851
+ }
852
+ }
853
+
854
+ // Copyright (c) Microsoft Corporation.
855
+ class SMEValidator extends Validator {
856
+ constructor(spec, options) {
857
+ super();
858
+ this.projectType = ProjectType.SME;
859
+ this.options = options;
860
+ this.spec = spec;
861
+ }
862
+ validateSpec() {
863
+ const result = { errors: [], warnings: [] };
864
+ // validate spec version
865
+ let validationResult = this.validateSpecVersion();
866
+ result.errors.push(...validationResult.errors);
867
+ // validate spec server
868
+ validationResult = this.validateSpecServer();
869
+ result.errors.push(...validationResult.errors);
870
+ // validate no supported API
871
+ validationResult = this.validateSpecNoSupportAPI();
872
+ result.errors.push(...validationResult.errors);
873
+ // validate operationId missing
874
+ if (this.options.allowMissingId) {
875
+ validationResult = this.validateSpecOperationId();
876
+ result.warnings.push(...validationResult.warnings);
877
+ }
878
+ return result;
879
+ }
880
+ validateAPI(method, path) {
881
+ const result = { isValid: true, reason: [] };
882
+ method = method.toLocaleLowerCase();
883
+ // validate method and path
884
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
885
+ if (!methodAndPathResult.isValid) {
886
+ return methodAndPathResult;
887
+ }
888
+ const operationObject = this.spec.paths[path][method];
889
+ // validate auth
890
+ const authCheckResult = this.validateAuth(method, path);
891
+ result.reason.push(...authCheckResult.reason);
892
+ // validate operationId
893
+ if (!this.options.allowMissingId && !operationObject.operationId) {
894
+ result.reason.push(ErrorType.MissingOperationId);
895
+ }
896
+ // validate server
897
+ const validateServerResult = this.validateServer(method, path);
898
+ result.reason.push(...validateServerResult.reason);
899
+ // validate response
900
+ const validateResponseResult = this.validateResponse(method, path);
901
+ result.reason.push(...validateResponseResult.reason);
902
+ let postBodyResult = {
903
+ requiredNum: 0,
904
+ optionalNum: 0,
905
+ isValid: true,
906
+ reason: [],
907
+ };
908
+ // validate requestBody
909
+ const requestBody = operationObject.requestBody;
910
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
911
+ if (Utils.containMultipleMediaTypes(requestBody)) {
912
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
913
+ }
914
+ if (requestJsonBody) {
915
+ const requestBodySchema = requestJsonBody.schema;
916
+ postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
917
+ result.reason.push(...postBodyResult.reason);
918
+ }
919
+ // validate parameters
920
+ const paramObject = operationObject.parameters;
921
+ const paramResult = this.checkParamSchema(paramObject);
922
+ result.reason.push(...paramResult.reason);
923
+ // validate total parameters count
924
+ if (paramResult.isValid && postBodyResult.isValid) {
925
+ const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
926
+ result.reason.push(...paramCountResult.reason);
927
+ }
928
+ if (result.reason.length > 0) {
929
+ result.isValid = false;
930
+ }
931
+ return result;
932
+ }
933
+ validateParamCount(postBodyResult, paramResult) {
934
+ const result = { isValid: true, reason: [] };
935
+ const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
936
+ const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
937
+ if (totalRequiredParams > 1) {
938
+ if (!this.options.allowMultipleParameters ||
939
+ totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
940
+ result.reason.push(ErrorType.ExceededRequiredParamsLimit);
941
+ }
942
+ }
943
+ else if (totalParams === 0) {
944
+ result.reason.push(ErrorType.NoParameter);
945
+ }
946
+ return result;
947
+ }
948
+ }
949
+ SMEValidator.SMERequiredParamsMaxNum = 5;
950
+
951
+ // Copyright (c) Microsoft Corporation.
952
+ class TeamsAIValidator extends Validator {
953
+ constructor(spec, options) {
954
+ super();
955
+ this.projectType = ProjectType.TeamsAi;
956
+ this.options = options;
957
+ this.spec = spec;
958
+ }
959
+ validateSpec() {
960
+ const result = { errors: [], warnings: [] };
961
+ // validate spec server
962
+ let validationResult = this.validateSpecServer();
963
+ result.errors.push(...validationResult.errors);
964
+ // validate no supported API
965
+ validationResult = this.validateSpecNoSupportAPI();
966
+ result.errors.push(...validationResult.errors);
967
+ return result;
968
+ }
969
+ validateAPI(method, path) {
970
+ const result = { isValid: true, reason: [] };
971
+ method = method.toLocaleLowerCase();
972
+ // validate method and path
973
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
974
+ if (!methodAndPathResult.isValid) {
975
+ return methodAndPathResult;
976
+ }
977
+ const operationObject = this.spec.paths[path][method];
978
+ // validate operationId
979
+ if (!this.options.allowMissingId && !operationObject.operationId) {
980
+ result.reason.push(ErrorType.MissingOperationId);
981
+ }
982
+ // validate server
983
+ const validateServerResult = this.validateServer(method, path);
984
+ result.reason.push(...validateServerResult.reason);
985
+ if (result.reason.length > 0) {
986
+ result.isValid = false;
987
+ }
988
+ return result;
989
+ }
990
+ }
991
+
992
+ class ValidatorFactory {
993
+ static create(spec, options) {
994
+ var _a;
995
+ const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : ProjectType.SME;
996
+ switch (type) {
997
+ case ProjectType.SME:
998
+ return new SMEValidator(spec, options);
999
+ case ProjectType.Copilot:
1000
+ return new CopilotValidator(spec, options);
1001
+ case ProjectType.TeamsAi:
1002
+ return new TeamsAIValidator(spec, options);
1003
+ default:
1004
+ throw new Error(`Invalid project type: ${type}`);
716
1005
  }
717
- return safeRegistrationIdEnvName;
718
1006
  }
719
1007
  }
720
1008
 
@@ -734,7 +1022,12 @@ class SpecParser {
734
1022
  allowSwagger: false,
735
1023
  allowAPIKeyAuth: false,
736
1024
  allowMultipleParameters: false,
1025
+ allowBearerTokenAuth: false,
737
1026
  allowOauth2: false,
1027
+ allowMethods: ["get", "post"],
1028
+ allowConversationStarters: false,
1029
+ allowResponseSemantics: false,
1030
+ projectType: ProjectType.SME,
738
1031
  };
739
1032
  this.pathOrSpec = pathOrDoc;
740
1033
  this.parser = new SwaggerParser();
@@ -749,11 +1042,7 @@ class SpecParser {
749
1042
  try {
750
1043
  try {
751
1044
  await this.loadSpec();
752
- await this.parser.validate(this.spec, {
753
- validate: {
754
- schema: false,
755
- },
756
- });
1045
+ await this.parser.validate(this.spec);
757
1046
  }
758
1047
  catch (e) {
759
1048
  return {
@@ -762,16 +1051,46 @@ class SpecParser {
762
1051
  errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
763
1052
  };
764
1053
  }
1054
+ const errors = [];
1055
+ const warnings = [];
765
1056
  if (!this.options.allowSwagger && this.isSwaggerFile) {
766
1057
  return {
767
1058
  status: ValidationStatus.Error,
768
1059
  warnings: [],
769
1060
  errors: [
770
- { type: ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1061
+ {
1062
+ type: ErrorType.SwaggerNotSupported,
1063
+ content: ConstantString.SwaggerNotSupported,
1064
+ },
771
1065
  ],
772
1066
  };
773
1067
  }
774
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1068
+ // Remote reference not supported
1069
+ const refPaths = this.parser.$refs.paths();
1070
+ // refPaths [0] is the current spec file path
1071
+ if (refPaths.length > 1) {
1072
+ errors.push({
1073
+ type: ErrorType.RemoteRefNotSupported,
1074
+ content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
1075
+ data: refPaths,
1076
+ });
1077
+ }
1078
+ const validator = this.getValidator(this.spec);
1079
+ const validationResult = validator.validateSpec();
1080
+ warnings.push(...validationResult.warnings);
1081
+ errors.push(...validationResult.errors);
1082
+ let status = ValidationStatus.Valid;
1083
+ if (warnings.length > 0 && errors.length === 0) {
1084
+ status = ValidationStatus.Warning;
1085
+ }
1086
+ else if (errors.length > 0) {
1087
+ status = ValidationStatus.Error;
1088
+ }
1089
+ return {
1090
+ status: status,
1091
+ warnings: warnings,
1092
+ errors: errors,
1093
+ };
775
1094
  }
776
1095
  catch (err) {
777
1096
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -780,17 +1099,20 @@ class SpecParser {
780
1099
  async listSupportedAPIInfo() {
781
1100
  try {
782
1101
  await this.loadSpec();
783
- const apiMap = this.getAllSupportedAPIs(this.spec);
1102
+ const apiMap = this.getAPIs(this.spec);
784
1103
  const apiInfos = [];
785
1104
  for (const key in apiMap) {
786
- const pathObjectItem = apiMap[key];
1105
+ const { operation, isValid } = apiMap[key];
1106
+ if (!isValid) {
1107
+ continue;
1108
+ }
787
1109
  const [method, path] = key.split(" ");
788
- const operationId = pathObjectItem.operationId;
1110
+ const operationId = operation.operationId;
789
1111
  // In Browser environment, this api is by default not support api without operationId
790
1112
  if (!operationId) {
791
1113
  continue;
792
1114
  }
793
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options.allowMultipleParameters);
1115
+ const command = Utils.parseApiInfo(operation, this.options);
794
1116
  const apiInfo = {
795
1117
  method: method,
796
1118
  path: path,
@@ -799,9 +1121,6 @@ class SpecParser {
799
1121
  parameters: command.parameters,
800
1122
  description: command.description,
801
1123
  };
802
- if (warning) {
803
- apiInfo.warning = warning;
804
- }
805
1124
  apiInfos.push(apiInfo);
806
1125
  }
807
1126
  return apiInfos;
@@ -827,6 +1146,17 @@ class SpecParser {
827
1146
  async getFilteredSpecs(filter, signal) {
828
1147
  throw new Error("Method not implemented.");
829
1148
  }
1149
+ /**
1150
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1151
+ * @param manifestPath A file path of the Teams app manifest file to update.
1152
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1153
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1154
+ * @param pluginFilePath File path of the api plugin file to generate.
1155
+ */
1156
+ // eslint-disable-next-line @typescript-eslint/require-await
1157
+ async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1158
+ throw new Error("Method not implemented.");
1159
+ }
830
1160
  /**
831
1161
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
832
1162
  * @param manifestPath A file path of the Teams app manifest file to update.
@@ -836,7 +1166,7 @@ class SpecParser {
836
1166
  * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
837
1167
  */
838
1168
  // eslint-disable-next-line @typescript-eslint/require-await
839
- async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal, isMe) {
1169
+ async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
840
1170
  throw new Error("Method not implemented.");
841
1171
  }
842
1172
  async loadSpec() {
@@ -849,13 +1179,18 @@ class SpecParser {
849
1179
  this.spec = (await this.parser.dereference(clonedUnResolveSpec));
850
1180
  }
851
1181
  }
852
- getAllSupportedAPIs(spec) {
853
- if (this.apiMap !== undefined) {
854
- return this.apiMap;
1182
+ getAPIs(spec) {
1183
+ const validator = this.getValidator(spec);
1184
+ const apiMap = validator.listAPIs();
1185
+ return apiMap;
1186
+ }
1187
+ getValidator(spec) {
1188
+ if (this.validator) {
1189
+ return this.validator;
855
1190
  }
856
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
857
- this.apiMap = result;
858
- return result;
1191
+ const validator = ValidatorFactory.create(spec, this.options);
1192
+ this.validator = validator;
1193
+ return validator;
859
1194
  }
860
1195
  }
861
1196
 
@@ -863,7 +1198,7 @@ class SpecParser {
863
1198
  class AdaptiveCardGenerator {
864
1199
  static generateAdaptiveCard(operationItem) {
865
1200
  try {
866
- const json = Utils.getResponseJson(operationItem);
1201
+ const { json } = Utils.getResponseJson(operationItem);
867
1202
  let cardBody = [];
868
1203
  let schema = json.schema;
869
1204
  let jsonPath = "$";