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