@microsoft/m365-spec-parser 0.1.1-alpha.c341ae107.0 → 0.1.1-alpha.c3fe84399.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;
338
192
  }
339
- static isAPIKeyAuth(authSchema) {
340
- return authSchema.type === "apiKey";
193
+ static isBearerTokenAuth(authScheme) {
194
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
341
195
  }
342
- static isBearerTokenAuth(authSchema) {
343
- return (authSchema.type === "oauth2" ||
344
- authSchema.type === "openIdConnect" ||
345
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
196
+ static isAPIKeyAuth(authScheme) {
197
+ return authScheme.type === "apiKey";
198
+ }
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
  }
@@ -367,24 +224,47 @@ class Utils {
367
224
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
368
225
  return result;
369
226
  }
227
+ static getAuthInfo(spec) {
228
+ let authInfo = undefined;
229
+ for (const url in spec.paths) {
230
+ for (const method in spec.paths[url]) {
231
+ const operation = spec.paths[url][method];
232
+ const authArray = Utils.getAuthArray(operation.security, spec);
233
+ if (authArray && authArray.length > 0) {
234
+ const currentAuth = authArray[0][0];
235
+ if (!authInfo) {
236
+ authInfo = authArray[0][0];
237
+ }
238
+ else if (authInfo.name !== currentAuth.name) {
239
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
240
+ }
241
+ }
242
+ }
243
+ }
244
+ return authInfo;
245
+ }
370
246
  static updateFirstLetter(str) {
371
247
  return str.charAt(0).toUpperCase() + str.slice(1);
372
248
  }
373
249
  static getResponseJson(operationObject) {
374
250
  var _a, _b;
375
251
  let json = {};
252
+ let multipleMediaType = false;
376
253
  for (const code of ConstantString.ResponseCodeFor20X) {
377
254
  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
255
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
256
+ multipleMediaType = false;
383
257
  json = responseObject.content["application/json"];
384
- break;
258
+ if (Utils.containMultipleMediaTypes(responseObject)) {
259
+ multipleMediaType = true;
260
+ json = {};
261
+ }
262
+ else {
263
+ break;
264
+ }
385
265
  }
386
266
  }
387
- return json;
267
+ return { json, multipleMediaType };
388
268
  }
389
269
  static convertPathToCamelCase(path) {
390
270
  const pathSegments = path.split(/[./{]/);
@@ -404,10 +284,10 @@ class Utils {
404
284
  return undefined;
405
285
  }
406
286
  }
407
- static resolveServerUrl(url) {
287
+ static resolveEnv(str) {
408
288
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
409
- let matches = placeHolderReg.exec(url);
410
- let newUrl = url;
289
+ let matches = placeHolderReg.exec(str);
290
+ let newStr = str;
411
291
  while (matches != null) {
412
292
  const envVar = matches[1];
413
293
  const envVal = process.env[envVar];
@@ -415,17 +295,17 @@ class Utils {
415
295
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
416
296
  }
417
297
  else {
418
- newUrl = newUrl.replace(matches[0], envVal);
298
+ newStr = newStr.replace(matches[0], envVal);
419
299
  }
420
- matches = placeHolderReg.exec(url);
300
+ matches = placeHolderReg.exec(str);
421
301
  }
422
- return newUrl;
302
+ return newStr;
423
303
  }
424
304
  static checkServerUrl(servers) {
425
305
  const errors = [];
426
306
  let serverUrl;
427
307
  try {
428
- serverUrl = Utils.resolveServerUrl(servers[0].url);
308
+ serverUrl = Utils.resolveEnv(servers[0].url);
429
309
  }
430
310
  catch (err) {
431
311
  errors.push({
@@ -455,7 +335,8 @@ class Utils {
455
335
  }
456
336
  return errors;
457
337
  }
458
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
338
+ static validateServer(spec, options) {
339
+ var _a;
459
340
  const errors = [];
460
341
  let hasTopLevelServers = false;
461
342
  let hasPathLevelServers = false;
@@ -476,7 +357,7 @@ class Utils {
476
357
  }
477
358
  for (const method in methods) {
478
359
  const operationObject = methods[method];
479
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
360
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
480
361
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
481
362
  hasOperationLevelServers = true;
482
363
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -519,6 +400,7 @@ class Utils {
519
400
  Utils.updateParameterWithInputType(schema, parameter);
520
401
  }
521
402
  if (isRequired && schema.default === undefined) {
403
+ parameter.isRequired = true;
522
404
  requiredParams.push(parameter);
523
405
  }
524
406
  else {
@@ -563,7 +445,7 @@ class Utils {
563
445
  param.value = schema.default;
564
446
  }
565
447
  }
566
- static parseApiInfo(operationItem, allowMultipleParameters) {
448
+ static parseApiInfo(operationItem, options) {
567
449
  var _a, _b;
568
450
  const requiredParams = [];
569
451
  const optionalParams = [];
@@ -577,11 +459,12 @@ class Utils {
577
459
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
578
460
  };
579
461
  const schema = param.schema;
580
- if (allowMultipleParameters && schema) {
462
+ if (options.allowMultipleParameters && schema) {
581
463
  Utils.updateParameterWithInputType(schema, parameter);
582
464
  }
583
465
  if (param.in !== "header" && param.in !== "cookie") {
584
466
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
467
+ parameter.isRequired = true;
585
468
  requiredParams.push(parameter);
586
469
  }
587
470
  else {
@@ -595,19 +478,13 @@ class Utils {
595
478
  const requestJson = requestBody.content["application/json"];
596
479
  if (Object.keys(requestJson).length !== 0) {
597
480
  const schema = requestJson.schema;
598
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
481
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
599
482
  requiredParams.push(...requiredP);
600
483
  optionalParams.push(...optionalP);
601
484
  }
602
485
  }
603
486
  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
- }
487
+ const parameters = [...requiredParams, ...optionalParams];
611
488
  const command = {
612
489
  context: ["compose"],
613
490
  type: "query",
@@ -616,105 +493,534 @@ class Utils {
616
493
  parameters: parameters,
617
494
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
618
495
  };
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
- };
496
+ return command;
497
+ }
498
+ static format(str, ...args) {
499
+ let index = 0;
500
+ return str.replace(/%s/g, () => {
501
+ const arg = args[index++];
502
+ return arg !== undefined ? arg : "";
503
+ });
504
+ }
505
+ static getSafeRegistrationIdEnvName(authName) {
506
+ if (!authName) {
507
+ return "";
626
508
  }
627
- return [command, warning];
509
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
510
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
511
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
512
+ }
513
+ return safeRegistrationIdEnvName;
628
514
  }
629
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
630
- const paths = spec.paths;
515
+ static getServerObject(spec, method, path) {
516
+ const pathObj = spec.paths[path];
517
+ const operationObject = pathObj[method];
518
+ const rootServer = spec.servers && spec.servers[0];
519
+ const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
520
+ const operationServer = operationObject.servers && operationObject.servers[0];
521
+ const serverUrl = operationServer || methodServer || rootServer;
522
+ return serverUrl;
523
+ }
524
+ }
525
+
526
+ // Copyright (c) Microsoft Corporation.
527
+ class Validator {
528
+ listAPIs() {
529
+ var _a;
530
+ if (this.apiMap) {
531
+ return this.apiMap;
532
+ }
533
+ const paths = this.spec.paths;
631
534
  const result = {};
632
535
  for (const path in paths) {
633
536
  const methods = paths[path];
634
537
  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;
538
+ const operationObject = methods[method];
539
+ if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
540
+ const validateResult = this.validateAPI(method, path);
541
+ result[`${method.toUpperCase()} ${path}`] = {
542
+ operation: operationObject,
543
+ isValid: validateResult.isValid,
544
+ reason: validateResult.reason,
545
+ };
639
546
  }
640
547
  }
641
548
  }
549
+ this.apiMap = result;
642
550
  return result;
643
551
  }
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,
552
+ validateSpecVersion() {
553
+ const result = { errors: [], warnings: [] };
554
+ if (this.spec.openapi >= "3.1.0") {
555
+ result.errors.push({
556
+ type: ErrorType.SpecVersionNotSupported,
557
+ content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
558
+ data: this.spec.openapi,
664
559
  });
665
560
  }
666
- // No supported API
667
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
668
- if (Object.keys(apiMap).length === 0) {
669
- errors.push({
561
+ return result;
562
+ }
563
+ validateSpecServer() {
564
+ const result = { errors: [], warnings: [] };
565
+ const serverErrors = Utils.validateServer(this.spec, this.options);
566
+ result.errors.push(...serverErrors);
567
+ return result;
568
+ }
569
+ validateSpecNoSupportAPI() {
570
+ const result = { errors: [], warnings: [] };
571
+ const apiMap = this.listAPIs();
572
+ const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
573
+ if (validAPIs.length === 0) {
574
+ const data = [];
575
+ for (const key in apiMap) {
576
+ const { reason } = apiMap[key];
577
+ const apiInvalidReason = { api: key, reason: reason };
578
+ data.push(apiInvalidReason);
579
+ }
580
+ result.errors.push({
670
581
  type: ErrorType.NoSupportedApi,
671
582
  content: ConstantString.NoSupportedApi,
583
+ data,
672
584
  });
673
585
  }
586
+ return result;
587
+ }
588
+ validateSpecOperationId() {
589
+ const result = { errors: [], warnings: [] };
590
+ const apiMap = this.listAPIs();
674
591
  // OperationId missing
675
592
  const apisMissingOperationId = [];
676
593
  for (const key in apiMap) {
677
- const pathObjectItem = apiMap[key];
678
- if (!pathObjectItem.operationId) {
594
+ const { operation } = apiMap[key];
595
+ if (!operation.operationId) {
679
596
  apisMissingOperationId.push(key);
680
597
  }
681
598
  }
682
599
  if (apisMissingOperationId.length > 0) {
683
- warnings.push({
600
+ result.warnings.push({
684
601
  type: WarningType.OperationIdMissing,
685
602
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
686
603
  data: apisMissingOperationId,
687
604
  });
688
605
  }
689
- let status = ValidationStatus.Valid;
690
- if (warnings.length > 0 && errors.length === 0) {
691
- status = ValidationStatus.Warning;
606
+ return result;
607
+ }
608
+ validateMethodAndPath(method, path) {
609
+ const result = { isValid: true, reason: [] };
610
+ if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
611
+ result.isValid = false;
612
+ result.reason.push(ErrorType.MethodNotAllowed);
613
+ return result;
614
+ }
615
+ const pathObj = this.spec.paths[path];
616
+ if (!pathObj || !pathObj[method]) {
617
+ result.isValid = false;
618
+ result.reason.push(ErrorType.UrlPathNotExist);
619
+ return result;
620
+ }
621
+ return result;
622
+ }
623
+ validateResponse(method, path) {
624
+ const result = { isValid: true, reason: [] };
625
+ const operationObject = this.spec.paths[path][method];
626
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
627
+ if (this.options.projectType === ProjectType.SME) {
628
+ // only support response body only contains “application/json” content type
629
+ if (multipleMediaType) {
630
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
631
+ }
632
+ else if (Object.keys(json).length === 0) {
633
+ // response body should not be empty
634
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
635
+ }
636
+ }
637
+ return result;
638
+ }
639
+ validateServer(method, path) {
640
+ const result = { isValid: true, reason: [] };
641
+ const serverObj = Utils.getServerObject(this.spec, method, path);
642
+ if (!serverObj) {
643
+ // should contain server URL
644
+ result.reason.push(ErrorType.NoServerInformation);
645
+ }
646
+ else {
647
+ // server url should be absolute url with https protocol
648
+ const serverValidateResult = Utils.checkServerUrl([serverObj]);
649
+ result.reason.push(...serverValidateResult.map((item) => item.type));
650
+ }
651
+ return result;
652
+ }
653
+ validateAuth(method, path) {
654
+ const pathObj = this.spec.paths[path];
655
+ const operationObject = pathObj[method];
656
+ const securities = operationObject.security;
657
+ const authSchemeArray = Utils.getAuthArray(securities, this.spec);
658
+ if (authSchemeArray.length === 0) {
659
+ return { isValid: true, reason: [] };
660
+ }
661
+ if (this.options.allowAPIKeyAuth ||
662
+ this.options.allowOauth2 ||
663
+ this.options.allowBearerTokenAuth) {
664
+ // Currently we don't support multiple auth in one operation
665
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
666
+ return {
667
+ isValid: false,
668
+ reason: [ErrorType.MultipleAuthNotSupported],
669
+ };
670
+ }
671
+ for (const auths of authSchemeArray) {
672
+ if (auths.length === 1) {
673
+ if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
674
+ (this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
675
+ (this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
676
+ return { isValid: true, reason: [] };
677
+ }
678
+ }
679
+ }
680
+ }
681
+ return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
682
+ }
683
+ checkPostBodySchema(schema, isRequired = false) {
684
+ var _a;
685
+ const paramResult = {
686
+ requiredNum: 0,
687
+ optionalNum: 0,
688
+ isValid: true,
689
+ reason: [],
690
+ };
691
+ if (Object.keys(schema).length === 0) {
692
+ return paramResult;
692
693
  }
693
- else if (errors.length > 0) {
694
- status = ValidationStatus.Error;
694
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
695
+ const isCopilot = this.projectType === ProjectType.Copilot;
696
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
697
+ paramResult.isValid = false;
698
+ paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
699
+ return paramResult;
695
700
  }
696
- return {
697
- status,
698
- warnings,
699
- errors,
701
+ if (schema.type === "string" ||
702
+ schema.type === "integer" ||
703
+ schema.type === "boolean" ||
704
+ schema.type === "number") {
705
+ if (isRequiredWithoutDefault) {
706
+ paramResult.requiredNum = paramResult.requiredNum + 1;
707
+ }
708
+ else {
709
+ paramResult.optionalNum = paramResult.optionalNum + 1;
710
+ }
711
+ }
712
+ else if (schema.type === "object") {
713
+ const { properties } = schema;
714
+ for (const property in properties) {
715
+ let isRequired = false;
716
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
717
+ isRequired = true;
718
+ }
719
+ const result = this.checkPostBodySchema(properties[property], isRequired);
720
+ paramResult.requiredNum += result.requiredNum;
721
+ paramResult.optionalNum += result.optionalNum;
722
+ paramResult.isValid = paramResult.isValid && result.isValid;
723
+ paramResult.reason.push(...result.reason);
724
+ }
725
+ }
726
+ else {
727
+ if (isRequiredWithoutDefault && !isCopilot) {
728
+ paramResult.isValid = false;
729
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
730
+ }
731
+ }
732
+ return paramResult;
733
+ }
734
+ checkParamSchema(paramObject) {
735
+ const paramResult = {
736
+ requiredNum: 0,
737
+ optionalNum: 0,
738
+ isValid: true,
739
+ reason: [],
700
740
  };
741
+ if (!paramObject) {
742
+ return paramResult;
743
+ }
744
+ const isCopilot = this.projectType === ProjectType.Copilot;
745
+ for (let i = 0; i < paramObject.length; i++) {
746
+ const param = paramObject[i];
747
+ const schema = param.schema;
748
+ if (isCopilot && this.hasNestedObjectInSchema(schema)) {
749
+ paramResult.isValid = false;
750
+ paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
751
+ continue;
752
+ }
753
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
754
+ if (isCopilot) {
755
+ if (isRequiredWithoutDefault) {
756
+ paramResult.requiredNum = paramResult.requiredNum + 1;
757
+ }
758
+ else {
759
+ paramResult.optionalNum = paramResult.optionalNum + 1;
760
+ }
761
+ continue;
762
+ }
763
+ if (param.in === "header" || param.in === "cookie") {
764
+ if (isRequiredWithoutDefault) {
765
+ paramResult.isValid = false;
766
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
767
+ }
768
+ continue;
769
+ }
770
+ if (schema.type !== "boolean" &&
771
+ schema.type !== "string" &&
772
+ schema.type !== "number" &&
773
+ schema.type !== "integer") {
774
+ if (isRequiredWithoutDefault) {
775
+ paramResult.isValid = false;
776
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
777
+ }
778
+ continue;
779
+ }
780
+ if (param.in === "query" || param.in === "path") {
781
+ if (isRequiredWithoutDefault) {
782
+ paramResult.requiredNum = paramResult.requiredNum + 1;
783
+ }
784
+ else {
785
+ paramResult.optionalNum = paramResult.optionalNum + 1;
786
+ }
787
+ }
788
+ }
789
+ return paramResult;
701
790
  }
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
- });
791
+ hasNestedObjectInSchema(schema) {
792
+ if (schema.type === "object") {
793
+ for (const property in schema.properties) {
794
+ const nestedSchema = schema.properties[property];
795
+ if (nestedSchema.type === "object") {
796
+ return true;
797
+ }
798
+ }
799
+ }
800
+ return false;
708
801
  }
709
- static getSafeRegistrationIdEnvName(authName) {
710
- if (!authName) {
711
- return "";
802
+ }
803
+
804
+ // Copyright (c) Microsoft Corporation.
805
+ class CopilotValidator extends Validator {
806
+ constructor(spec, options) {
807
+ super();
808
+ this.projectType = ProjectType.Copilot;
809
+ this.options = options;
810
+ this.spec = spec;
811
+ }
812
+ validateSpec() {
813
+ const result = { errors: [], warnings: [] };
814
+ // validate spec version
815
+ let validationResult = this.validateSpecVersion();
816
+ result.errors.push(...validationResult.errors);
817
+ // validate spec server
818
+ validationResult = this.validateSpecServer();
819
+ result.errors.push(...validationResult.errors);
820
+ // validate no supported API
821
+ validationResult = this.validateSpecNoSupportAPI();
822
+ result.errors.push(...validationResult.errors);
823
+ // validate operationId missing
824
+ validationResult = this.validateSpecOperationId();
825
+ result.warnings.push(...validationResult.warnings);
826
+ return result;
827
+ }
828
+ validateAPI(method, path) {
829
+ const result = { isValid: true, reason: [] };
830
+ method = method.toLocaleLowerCase();
831
+ // validate method and path
832
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
833
+ if (!methodAndPathResult.isValid) {
834
+ return methodAndPathResult;
712
835
  }
713
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
714
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
715
- safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
836
+ const operationObject = this.spec.paths[path][method];
837
+ // validate auth
838
+ const authCheckResult = this.validateAuth(method, path);
839
+ result.reason.push(...authCheckResult.reason);
840
+ // validate operationId
841
+ if (!this.options.allowMissingId && !operationObject.operationId) {
842
+ result.reason.push(ErrorType.MissingOperationId);
843
+ }
844
+ // validate server
845
+ const validateServerResult = this.validateServer(method, path);
846
+ result.reason.push(...validateServerResult.reason);
847
+ // validate response
848
+ const validateResponseResult = this.validateResponse(method, path);
849
+ result.reason.push(...validateResponseResult.reason);
850
+ // validate requestBody
851
+ const requestBody = operationObject.requestBody;
852
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
853
+ if (requestJsonBody) {
854
+ const requestBodySchema = requestJsonBody.schema;
855
+ if (requestBodySchema.type !== "object") {
856
+ result.reason.push(ErrorType.PostBodySchemaIsNotJson);
857
+ }
858
+ const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
859
+ result.reason.push(...requestBodyParamResult.reason);
860
+ }
861
+ // validate parameters
862
+ const paramObject = operationObject.parameters;
863
+ const paramResult = this.checkParamSchema(paramObject);
864
+ result.reason.push(...paramResult.reason);
865
+ if (result.reason.length > 0) {
866
+ result.isValid = false;
867
+ }
868
+ return result;
869
+ }
870
+ }
871
+
872
+ // Copyright (c) Microsoft Corporation.
873
+ class SMEValidator extends Validator {
874
+ constructor(spec, options) {
875
+ super();
876
+ this.projectType = ProjectType.SME;
877
+ this.options = options;
878
+ this.spec = spec;
879
+ }
880
+ validateSpec() {
881
+ const result = { errors: [], warnings: [] };
882
+ // validate spec version
883
+ let validationResult = this.validateSpecVersion();
884
+ result.errors.push(...validationResult.errors);
885
+ // validate spec server
886
+ validationResult = this.validateSpecServer();
887
+ result.errors.push(...validationResult.errors);
888
+ // validate no supported API
889
+ validationResult = this.validateSpecNoSupportAPI();
890
+ result.errors.push(...validationResult.errors);
891
+ // validate operationId missing
892
+ if (this.options.allowMissingId) {
893
+ validationResult = this.validateSpecOperationId();
894
+ result.warnings.push(...validationResult.warnings);
895
+ }
896
+ return result;
897
+ }
898
+ validateAPI(method, path) {
899
+ const result = { isValid: true, reason: [] };
900
+ method = method.toLocaleLowerCase();
901
+ // validate method and path
902
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
903
+ if (!methodAndPathResult.isValid) {
904
+ return methodAndPathResult;
905
+ }
906
+ const operationObject = this.spec.paths[path][method];
907
+ // validate auth
908
+ const authCheckResult = this.validateAuth(method, path);
909
+ result.reason.push(...authCheckResult.reason);
910
+ // validate operationId
911
+ if (!this.options.allowMissingId && !operationObject.operationId) {
912
+ result.reason.push(ErrorType.MissingOperationId);
913
+ }
914
+ // validate server
915
+ const validateServerResult = this.validateServer(method, path);
916
+ result.reason.push(...validateServerResult.reason);
917
+ // validate response
918
+ const validateResponseResult = this.validateResponse(method, path);
919
+ result.reason.push(...validateResponseResult.reason);
920
+ let postBodyResult = {
921
+ requiredNum: 0,
922
+ optionalNum: 0,
923
+ isValid: true,
924
+ reason: [],
925
+ };
926
+ // validate requestBody
927
+ const requestBody = operationObject.requestBody;
928
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
929
+ if (Utils.containMultipleMediaTypes(requestBody)) {
930
+ result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
931
+ }
932
+ if (requestJsonBody) {
933
+ const requestBodySchema = requestJsonBody.schema;
934
+ postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
935
+ result.reason.push(...postBodyResult.reason);
936
+ }
937
+ // validate parameters
938
+ const paramObject = operationObject.parameters;
939
+ const paramResult = this.checkParamSchema(paramObject);
940
+ result.reason.push(...paramResult.reason);
941
+ // validate total parameters count
942
+ if (paramResult.isValid && postBodyResult.isValid) {
943
+ const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
944
+ result.reason.push(...paramCountResult.reason);
945
+ }
946
+ if (result.reason.length > 0) {
947
+ result.isValid = false;
948
+ }
949
+ return result;
950
+ }
951
+ validateParamCount(postBodyResult, paramResult) {
952
+ const result = { isValid: true, reason: [] };
953
+ const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
954
+ const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
955
+ if (totalRequiredParams > 1) {
956
+ if (!this.options.allowMultipleParameters ||
957
+ totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
958
+ result.reason.push(ErrorType.ExceededRequiredParamsLimit);
959
+ }
960
+ }
961
+ else if (totalParams === 0) {
962
+ result.reason.push(ErrorType.NoParameter);
963
+ }
964
+ return result;
965
+ }
966
+ }
967
+ SMEValidator.SMERequiredParamsMaxNum = 5;
968
+
969
+ // Copyright (c) Microsoft Corporation.
970
+ class TeamsAIValidator extends Validator {
971
+ constructor(spec, options) {
972
+ super();
973
+ this.projectType = ProjectType.TeamsAi;
974
+ this.options = options;
975
+ this.spec = spec;
976
+ }
977
+ validateSpec() {
978
+ const result = { errors: [], warnings: [] };
979
+ // validate spec server
980
+ let validationResult = this.validateSpecServer();
981
+ result.errors.push(...validationResult.errors);
982
+ // validate no supported API
983
+ validationResult = this.validateSpecNoSupportAPI();
984
+ result.errors.push(...validationResult.errors);
985
+ return result;
986
+ }
987
+ validateAPI(method, path) {
988
+ const result = { isValid: true, reason: [] };
989
+ method = method.toLocaleLowerCase();
990
+ // validate method and path
991
+ const methodAndPathResult = this.validateMethodAndPath(method, path);
992
+ if (!methodAndPathResult.isValid) {
993
+ return methodAndPathResult;
994
+ }
995
+ const operationObject = this.spec.paths[path][method];
996
+ // validate operationId
997
+ if (!this.options.allowMissingId && !operationObject.operationId) {
998
+ result.reason.push(ErrorType.MissingOperationId);
999
+ }
1000
+ // validate server
1001
+ const validateServerResult = this.validateServer(method, path);
1002
+ result.reason.push(...validateServerResult.reason);
1003
+ if (result.reason.length > 0) {
1004
+ result.isValid = false;
1005
+ }
1006
+ return result;
1007
+ }
1008
+ }
1009
+
1010
+ class ValidatorFactory {
1011
+ static create(spec, options) {
1012
+ var _a;
1013
+ const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : ProjectType.SME;
1014
+ switch (type) {
1015
+ case ProjectType.SME:
1016
+ return new SMEValidator(spec, options);
1017
+ case ProjectType.Copilot:
1018
+ return new CopilotValidator(spec, options);
1019
+ case ProjectType.TeamsAi:
1020
+ return new TeamsAIValidator(spec, options);
1021
+ default:
1022
+ throw new Error(`Invalid project type: ${type}`);
716
1023
  }
717
- return safeRegistrationIdEnvName;
718
1024
  }
719
1025
  }
720
1026
 
@@ -734,7 +1040,12 @@ class SpecParser {
734
1040
  allowSwagger: false,
735
1041
  allowAPIKeyAuth: false,
736
1042
  allowMultipleParameters: false,
1043
+ allowBearerTokenAuth: false,
737
1044
  allowOauth2: false,
1045
+ allowMethods: ["get", "post"],
1046
+ allowConversationStarters: false,
1047
+ allowResponseSemantics: false,
1048
+ projectType: ProjectType.SME,
738
1049
  };
739
1050
  this.pathOrSpec = pathOrDoc;
740
1051
  this.parser = new SwaggerParser();
@@ -749,11 +1060,7 @@ class SpecParser {
749
1060
  try {
750
1061
  try {
751
1062
  await this.loadSpec();
752
- await this.parser.validate(this.spec, {
753
- validate: {
754
- schema: false,
755
- },
756
- });
1063
+ await this.parser.validate(this.spec);
757
1064
  }
758
1065
  catch (e) {
759
1066
  return {
@@ -762,16 +1069,46 @@ class SpecParser {
762
1069
  errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
763
1070
  };
764
1071
  }
1072
+ const errors = [];
1073
+ const warnings = [];
765
1074
  if (!this.options.allowSwagger && this.isSwaggerFile) {
766
1075
  return {
767
1076
  status: ValidationStatus.Error,
768
1077
  warnings: [],
769
1078
  errors: [
770
- { type: ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1079
+ {
1080
+ type: ErrorType.SwaggerNotSupported,
1081
+ content: ConstantString.SwaggerNotSupported,
1082
+ },
771
1083
  ],
772
1084
  };
773
1085
  }
774
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1086
+ // Remote reference not supported
1087
+ const refPaths = this.parser.$refs.paths();
1088
+ // refPaths [0] is the current spec file path
1089
+ if (refPaths.length > 1) {
1090
+ errors.push({
1091
+ type: ErrorType.RemoteRefNotSupported,
1092
+ content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
1093
+ data: refPaths,
1094
+ });
1095
+ }
1096
+ const validator = this.getValidator(this.spec);
1097
+ const validationResult = validator.validateSpec();
1098
+ warnings.push(...validationResult.warnings);
1099
+ errors.push(...validationResult.errors);
1100
+ let status = ValidationStatus.Valid;
1101
+ if (warnings.length > 0 && errors.length === 0) {
1102
+ status = ValidationStatus.Warning;
1103
+ }
1104
+ else if (errors.length > 0) {
1105
+ status = ValidationStatus.Error;
1106
+ }
1107
+ return {
1108
+ status: status,
1109
+ warnings: warnings,
1110
+ errors: errors,
1111
+ };
775
1112
  }
776
1113
  catch (err) {
777
1114
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -780,17 +1117,20 @@ class SpecParser {
780
1117
  async listSupportedAPIInfo() {
781
1118
  try {
782
1119
  await this.loadSpec();
783
- const apiMap = this.getAllSupportedAPIs(this.spec);
1120
+ const apiMap = this.getAPIs(this.spec);
784
1121
  const apiInfos = [];
785
1122
  for (const key in apiMap) {
786
- const pathObjectItem = apiMap[key];
1123
+ const { operation, isValid } = apiMap[key];
1124
+ if (!isValid) {
1125
+ continue;
1126
+ }
787
1127
  const [method, path] = key.split(" ");
788
- const operationId = pathObjectItem.operationId;
1128
+ const operationId = operation.operationId;
789
1129
  // In Browser environment, this api is by default not support api without operationId
790
1130
  if (!operationId) {
791
1131
  continue;
792
1132
  }
793
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options.allowMultipleParameters);
1133
+ const command = Utils.parseApiInfo(operation, this.options);
794
1134
  const apiInfo = {
795
1135
  method: method,
796
1136
  path: path,
@@ -799,9 +1139,6 @@ class SpecParser {
799
1139
  parameters: command.parameters,
800
1140
  description: command.description,
801
1141
  };
802
- if (warning) {
803
- apiInfo.warning = warning;
804
- }
805
1142
  apiInfos.push(apiInfo);
806
1143
  }
807
1144
  return apiInfos;
@@ -827,6 +1164,17 @@ class SpecParser {
827
1164
  async getFilteredSpecs(filter, signal) {
828
1165
  throw new Error("Method not implemented.");
829
1166
  }
1167
+ /**
1168
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1169
+ * @param manifestPath A file path of the Teams app manifest file to update.
1170
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1171
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1172
+ * @param pluginFilePath File path of the api plugin file to generate.
1173
+ */
1174
+ // eslint-disable-next-line @typescript-eslint/require-await
1175
+ async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1176
+ throw new Error("Method not implemented.");
1177
+ }
830
1178
  /**
831
1179
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
832
1180
  * @param manifestPath A file path of the Teams app manifest file to update.
@@ -836,7 +1184,7 @@ class SpecParser {
836
1184
  * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
837
1185
  */
838
1186
  // eslint-disable-next-line @typescript-eslint/require-await
839
- async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal, isMe) {
1187
+ async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
840
1188
  throw new Error("Method not implemented.");
841
1189
  }
842
1190
  async loadSpec() {
@@ -849,13 +1197,18 @@ class SpecParser {
849
1197
  this.spec = (await this.parser.dereference(clonedUnResolveSpec));
850
1198
  }
851
1199
  }
852
- getAllSupportedAPIs(spec) {
853
- if (this.apiMap !== undefined) {
854
- return this.apiMap;
1200
+ getAPIs(spec) {
1201
+ const validator = this.getValidator(spec);
1202
+ const apiMap = validator.listAPIs();
1203
+ return apiMap;
1204
+ }
1205
+ getValidator(spec) {
1206
+ if (this.validator) {
1207
+ return this.validator;
855
1208
  }
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;
1209
+ const validator = ValidatorFactory.create(spec, this.options);
1210
+ this.validator = validator;
1211
+ return validator;
859
1212
  }
860
1213
  }
861
1214
 
@@ -863,7 +1216,7 @@ class SpecParser {
863
1216
  class AdaptiveCardGenerator {
864
1217
  static generateAdaptiveCard(operationItem) {
865
1218
  try {
866
- const json = Utils.getResponseJson(operationItem);
1219
+ const { json } = Utils.getResponseJson(operationItem);
867
1220
  let cardBody = [];
868
1221
  let schema = json.schema;
869
1222
  let jsonPath = "$";