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