@microsoft/m365-spec-parser 0.1.1-alpha.cf377d39f.0 → 0.1.1-alpha.d292dc740.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,9 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
73
95
  ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
74
96
  ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
75
97
  ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
76
- ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
98
+ ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
99
+ ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
100
+ ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
77
101
  ConstantString.WrappedCardVersion = "devPreview";
78
102
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
79
103
  ConstantString.WrappedCardResponseLayout = "list";
@@ -83,8 +107,14 @@ ConstantString.AdaptiveCardVersion = "1.5";
83
107
  ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
84
108
  ConstantString.AdaptiveCardType = "AdaptiveCard";
85
109
  ConstantString.TextBlockType = "TextBlock";
110
+ ConstantString.ImageType = "Image";
86
111
  ConstantString.ContainerType = "Container";
87
- ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
112
+ ConstantString.RegistrationIdPostfix = {
113
+ apiKey: "REGISTRATION_ID",
114
+ oauth2: "CONFIGURATION_ID",
115
+ http: "REGISTRATION_ID",
116
+ openIdConnect: "REGISTRATION_ID",
117
+ };
88
118
  ConstantString.ResponseCodeFor20X = [
89
119
  "200",
90
120
  "201",
@@ -143,219 +173,52 @@ ConstantString.ShortDescriptionMaxLens = 80;
143
173
  ConstantString.FullDescriptionMaxLens = 4000;
144
174
  ConstantString.CommandDescriptionMaxLens = 128;
145
175
  ConstantString.ParameterDescriptionMaxLens = 128;
176
+ ConstantString.ConversationStarterMaxLens = 50;
146
177
  ConstantString.CommandTitleMaxLens = 32;
147
- ConstantString.ParameterTitleMaxLens = 32;
178
+ ConstantString.ParameterTitleMaxLens = 32;
179
+ ConstantString.SMERequiredParamsMaxNum = 5;
180
+ ConstantString.DefaultPluginId = "plugin_1";
148
181
 
149
182
  // Copyright (c) Microsoft Corporation.
150
183
  class Utils {
151
- static checkParameters(paramObject) {
152
- const paramResult = {
153
- requiredNum: 0,
154
- optionalNum: 0,
155
- isValid: true,
156
- };
157
- if (!paramObject) {
158
- return paramResult;
159
- }
160
- for (let i = 0; i < paramObject.length; i++) {
161
- const param = paramObject[i];
162
- const schema = param.schema;
163
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
164
- if (param.in === "header" || param.in === "cookie") {
165
- if (isRequiredWithoutDefault) {
166
- paramResult.isValid = false;
167
- }
168
- continue;
169
- }
170
- if (schema.type !== "boolean" &&
171
- schema.type !== "string" &&
172
- schema.type !== "number" &&
173
- schema.type !== "integer") {
174
- if (isRequiredWithoutDefault) {
175
- paramResult.isValid = false;
176
- }
177
- continue;
178
- }
179
- if (param.in === "query" || param.in === "path") {
180
- if (isRequiredWithoutDefault) {
181
- paramResult.requiredNum = paramResult.requiredNum + 1;
182
- }
183
- else {
184
- paramResult.optionalNum = paramResult.optionalNum + 1;
185
- }
186
- }
187
- }
188
- return paramResult;
189
- }
190
- static checkPostBody(schema, isRequired = false) {
191
- var _a;
192
- const paramResult = {
193
- requiredNum: 0,
194
- optionalNum: 0,
195
- isValid: true,
196
- };
197
- if (Object.keys(schema).length === 0) {
198
- return paramResult;
199
- }
200
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
201
- if (schema.type === "string" ||
202
- schema.type === "integer" ||
203
- schema.type === "boolean" ||
204
- schema.type === "number") {
205
- if (isRequiredWithoutDefault) {
206
- paramResult.requiredNum = paramResult.requiredNum + 1;
207
- }
208
- else {
209
- paramResult.optionalNum = paramResult.optionalNum + 1;
210
- }
211
- }
212
- else if (schema.type === "object") {
213
- const { properties } = schema;
214
- for (const property in properties) {
215
- let isRequired = false;
216
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
217
- isRequired = true;
218
- }
219
- const result = Utils.checkPostBody(properties[property], isRequired);
220
- paramResult.requiredNum += result.requiredNum;
221
- paramResult.optionalNum += result.optionalNum;
222
- paramResult.isValid = paramResult.isValid && result.isValid;
223
- }
224
- }
225
- else {
226
- if (isRequiredWithoutDefault) {
227
- paramResult.isValid = false;
228
- }
229
- }
230
- return paramResult;
231
- }
232
- /**
233
- * Checks if the given API is supported.
234
- * @param {string} method - The HTTP method of the API.
235
- * @param {string} path - The path of the API.
236
- * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
237
- * @returns {boolean} - Returns true if the API is supported, false otherwise.
238
- * @description The following APIs are supported:
239
- * 1. only support Get/Post operation without auth property
240
- * 2. parameter inside query or path only support string, number, boolean and integer
241
- * 3. parameter inside post body only support string, number, boolean, integer and object
242
- * 4. request body + required parameters <= 1
243
- * 5. response body should be “application/json” and not empty, and response code should be 20X
244
- * 6. only support request body with “application/json” content type
245
- */
246
- static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
247
- const pathObj = spec.paths[path];
248
- method = method.toLocaleLowerCase();
249
- if (pathObj) {
250
- if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
251
- pathObj[method]) {
252
- const securities = pathObj[method].security;
253
- const authArray = Utils.getAuthArray(securities, spec);
254
- if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
255
- return false;
256
- }
257
- const operationObject = pathObj[method];
258
- if (!allowMissingId && !operationObject.operationId) {
259
- return false;
260
- }
261
- const paramObject = operationObject.parameters;
262
- const requestBody = operationObject.requestBody;
263
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
264
- const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
265
- if (mediaTypesCount > 1) {
266
- return false;
267
- }
268
- const responseJson = Utils.getResponseJson(operationObject);
269
- if (Object.keys(responseJson).length === 0) {
270
- return false;
271
- }
272
- let requestBodyParamResult = {
273
- requiredNum: 0,
274
- optionalNum: 0,
275
- isValid: true,
276
- };
277
- if (requestJsonBody) {
278
- const requestBodySchema = requestJsonBody.schema;
279
- requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
280
- }
281
- if (!requestBodyParamResult.isValid) {
282
- return false;
283
- }
284
- const paramResult = Utils.checkParameters(paramObject);
285
- if (!paramResult.isValid) {
286
- return false;
287
- }
288
- if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
289
- if (allowMultipleParameters &&
290
- requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
291
- return true;
292
- }
293
- return false;
294
- }
295
- else if (requestBodyParamResult.requiredNum +
296
- requestBodyParamResult.optionalNum +
297
- paramResult.requiredNum +
298
- paramResult.optionalNum ===
299
- 0) {
300
- return false;
301
- }
302
- else {
184
+ static hasNestedObjectInSchema(schema) {
185
+ if (schema.type === "object") {
186
+ for (const property in schema.properties) {
187
+ const nestedSchema = schema.properties[property];
188
+ if (nestedSchema.type === "object") {
303
189
  return true;
304
190
  }
305
191
  }
306
192
  }
307
193
  return false;
308
194
  }
309
- static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
310
- if (authSchemaArray.length === 0) {
311
- return true;
312
- }
313
- if (allowAPIKeyAuth || allowOauth2) {
314
- // Currently we don't support multiple auth in one operation
315
- if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
316
- return false;
317
- }
318
- for (const auths of authSchemaArray) {
319
- if (auths.length === 1) {
320
- if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
321
- return true;
322
- }
323
- else if (!allowAPIKeyAuth &&
324
- allowOauth2 &&
325
- Utils.isBearerTokenAuth(auths[0].authSchema)) {
326
- return true;
327
- }
328
- else if (allowAPIKeyAuth &&
329
- allowOauth2 &&
330
- (Utils.isAPIKeyAuth(auths[0].authSchema) ||
331
- Utils.isBearerTokenAuth(auths[0].authSchema))) {
332
- return true;
333
- }
334
- }
335
- }
336
- }
337
- return false;
195
+ static containMultipleMediaTypes(bodyObject) {
196
+ return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
338
197
  }
339
- static isAPIKeyAuth(authSchema) {
340
- return authSchema.type === "apiKey";
198
+ static isBearerTokenAuth(authScheme) {
199
+ return authScheme.type === "http" && authScheme.scheme === "bearer";
341
200
  }
342
- static isBearerTokenAuth(authSchema) {
343
- return (authSchema.type === "oauth2" ||
344
- authSchema.type === "openIdConnect" ||
345
- (authSchema.type === "http" && authSchema.scheme === "bearer"));
201
+ static isAPIKeyAuth(authScheme) {
202
+ return authScheme.type === "apiKey";
203
+ }
204
+ static isOAuthWithAuthCodeFlow(authScheme) {
205
+ return !!(authScheme.type === "oauth2" &&
206
+ authScheme.flows &&
207
+ authScheme.flows.authorizationCode);
346
208
  }
347
209
  static getAuthArray(securities, spec) {
348
210
  var _a;
349
211
  const result = [];
350
212
  const securitySchemas = (_a = spec.components) === null || _a === void 0 ? void 0 : _a.securitySchemes;
351
- if (securities && securitySchemas) {
352
- for (let i = 0; i < securities.length; i++) {
353
- 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];
354
217
  const authArray = [];
355
218
  for (const name in security) {
356
219
  const auth = securitySchemas[name];
357
220
  authArray.push({
358
- authSchema: auth,
221
+ authScheme: auth,
359
222
  name: name,
360
223
  });
361
224
  }
@@ -367,24 +230,47 @@ class Utils {
367
230
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
368
231
  return result;
369
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
+ }
370
252
  static updateFirstLetter(str) {
371
253
  return str.charAt(0).toUpperCase() + str.slice(1);
372
254
  }
373
255
  static getResponseJson(operationObject) {
374
256
  var _a, _b;
375
257
  let json = {};
258
+ let multipleMediaType = false;
376
259
  for (const code of ConstantString.ResponseCodeFor20X) {
377
260
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
378
- const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
379
- if (mediaTypesCount > 1) {
380
- return {};
381
- }
382
261
  if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
262
+ multipleMediaType = false;
383
263
  json = responseObject.content["application/json"];
384
- break;
264
+ if (Utils.containMultipleMediaTypes(responseObject)) {
265
+ multipleMediaType = true;
266
+ json = {};
267
+ }
268
+ else {
269
+ break;
270
+ }
385
271
  }
386
272
  }
387
- return json;
273
+ return { json, multipleMediaType };
388
274
  }
389
275
  static convertPathToCamelCase(path) {
390
276
  const pathSegments = path.split(/[./{]/);
@@ -404,10 +290,10 @@ class Utils {
404
290
  return undefined;
405
291
  }
406
292
  }
407
- static resolveServerUrl(url) {
293
+ static resolveEnv(str) {
408
294
  const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
409
- let matches = placeHolderReg.exec(url);
410
- let newUrl = url;
295
+ let matches = placeHolderReg.exec(str);
296
+ let newStr = str;
411
297
  while (matches != null) {
412
298
  const envVar = matches[1];
413
299
  const envVal = process.env[envVar];
@@ -415,17 +301,17 @@ class Utils {
415
301
  throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
416
302
  }
417
303
  else {
418
- newUrl = newUrl.replace(matches[0], envVal);
304
+ newStr = newStr.replace(matches[0], envVal);
419
305
  }
420
- matches = placeHolderReg.exec(url);
306
+ matches = placeHolderReg.exec(str);
421
307
  }
422
- return newUrl;
308
+ return newStr;
423
309
  }
424
310
  static checkServerUrl(servers) {
425
311
  const errors = [];
426
312
  let serverUrl;
427
313
  try {
428
- serverUrl = Utils.resolveServerUrl(servers[0].url);
314
+ serverUrl = Utils.resolveEnv(servers[0].url);
429
315
  }
430
316
  catch (err) {
431
317
  errors.push({
@@ -455,7 +341,8 @@ class Utils {
455
341
  }
456
342
  return errors;
457
343
  }
458
- static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
344
+ static validateServer(spec, options) {
345
+ var _a;
459
346
  const errors = [];
460
347
  let hasTopLevelServers = false;
461
348
  let hasPathLevelServers = false;
@@ -476,7 +363,7 @@ class Utils {
476
363
  }
477
364
  for (const method in methods) {
478
365
  const operationObject = methods[method];
479
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
366
+ if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
480
367
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
481
368
  hasOperationLevelServers = true;
482
369
  const serverErrors = Utils.checkServerUrl(operationObject.servers);
@@ -519,6 +406,7 @@ class Utils {
519
406
  Utils.updateParameterWithInputType(schema, parameter);
520
407
  }
521
408
  if (isRequired && schema.default === undefined) {
409
+ parameter.isRequired = true;
522
410
  requiredParams.push(parameter);
523
411
  }
524
412
  else {
@@ -563,7 +451,7 @@ class Utils {
563
451
  param.value = schema.default;
564
452
  }
565
453
  }
566
- static parseApiInfo(operationItem, allowMultipleParameters) {
454
+ static parseApiInfo(operationItem, options) {
567
455
  var _a, _b;
568
456
  const requiredParams = [];
569
457
  const optionalParams = [];
@@ -577,11 +465,12 @@ class Utils {
577
465
  description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
578
466
  };
579
467
  const schema = param.schema;
580
- if (allowMultipleParameters && schema) {
468
+ if (options.allowMultipleParameters && schema) {
581
469
  Utils.updateParameterWithInputType(schema, parameter);
582
470
  }
583
471
  if (param.in !== "header" && param.in !== "cookie") {
584
472
  if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
473
+ parameter.isRequired = true;
585
474
  requiredParams.push(parameter);
586
475
  }
587
476
  else {
@@ -595,19 +484,13 @@ class Utils {
595
484
  const requestJson = requestBody.content["application/json"];
596
485
  if (Object.keys(requestJson).length !== 0) {
597
486
  const schema = requestJson.schema;
598
- const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
487
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
599
488
  requiredParams.push(...requiredP);
600
489
  optionalParams.push(...optionalP);
601
490
  }
602
491
  }
603
492
  const operationId = operationItem.operationId;
604
- const parameters = [];
605
- if (requiredParams.length !== 0) {
606
- parameters.push(...requiredParams);
607
- }
608
- else {
609
- parameters.push(optionalParams[0]);
610
- }
493
+ const parameters = [...requiredParams, ...optionalParams];
611
494
  const command = {
612
495
  context: ["compose"],
613
496
  type: "query",
@@ -616,105 +499,534 @@ class Utils {
616
499
  parameters: parameters,
617
500
  description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
618
501
  };
619
- let warning = undefined;
620
- if (requiredParams.length === 0 && optionalParams.length > 1) {
621
- warning = {
622
- type: WarningType.OperationOnlyContainsOptionalParam,
623
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
624
- data: operationId,
625
- };
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 "";
626
514
  }
627
- 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;
628
520
  }
629
- static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
630
- 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;
631
540
  const result = {};
632
541
  for (const path in paths) {
633
542
  const methods = paths[path];
634
543
  for (const method in methods) {
635
- // For developer preview, only support GET operation with only 1 parameter without auth
636
- if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
637
- const operationObject = methods[method];
638
- result[`${method.toUpperCase()} ${path}`] = operationObject;
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
+ };
639
552
  }
640
553
  }
641
554
  }
555
+ this.apiMap = result;
642
556
  return result;
643
557
  }
644
- static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
645
- const errors = [];
646
- const warnings = [];
647
- if (isSwaggerFile) {
648
- warnings.push({
649
- type: WarningType.ConvertSwaggerToOpenAPI,
650
- content: ConstantString.ConvertSwaggerToOpenAPI,
651
- });
652
- }
653
- // Server validation
654
- const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
655
- errors.push(...serverErrors);
656
- // Remote reference not supported
657
- const refPaths = parser.$refs.paths();
658
- // refPaths [0] is the current spec file path
659
- if (refPaths.length > 1) {
660
- errors.push({
661
- type: ErrorType.RemoteRefNotSupported,
662
- content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
663
- data: refPaths,
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,
664
565
  });
665
566
  }
666
- // No supported API
667
- const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
668
- if (Object.keys(apiMap).length === 0) {
669
- 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({
670
587
  type: ErrorType.NoSupportedApi,
671
588
  content: ConstantString.NoSupportedApi,
589
+ data,
672
590
  });
673
591
  }
592
+ return result;
593
+ }
594
+ validateSpecOperationId() {
595
+ const result = { errors: [], warnings: [] };
596
+ const apiMap = this.listAPIs();
674
597
  // OperationId missing
675
598
  const apisMissingOperationId = [];
676
599
  for (const key in apiMap) {
677
- const pathObjectItem = apiMap[key];
678
- if (!pathObjectItem.operationId) {
600
+ const { operation } = apiMap[key];
601
+ if (!operation.operationId) {
679
602
  apisMissingOperationId.push(key);
680
603
  }
681
604
  }
682
605
  if (apisMissingOperationId.length > 0) {
683
- warnings.push({
606
+ result.warnings.push({
684
607
  type: WarningType.OperationIdMissing,
685
608
  content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
686
609
  data: apisMissingOperationId,
687
610
  });
688
611
  }
689
- let status = ValidationStatus.Valid;
690
- if (warnings.length > 0 && errors.length === 0) {
691
- 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));
656
+ }
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
+ }
686
+ }
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: [],
696
+ };
697
+ if (Object.keys(schema).length === 0) {
698
+ return paramResult;
692
699
  }
693
- else if (errors.length > 0) {
694
- status = ValidationStatus.Error;
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;
695
706
  }
696
- return {
697
- status,
698
- warnings,
699
- errors,
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;
739
+ }
740
+ checkParamSchema(paramObject) {
741
+ const paramResult = {
742
+ requiredNum: 0,
743
+ optionalNum: 0,
744
+ isValid: true,
745
+ reason: [],
700
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;
701
796
  }
702
- static format(str, ...args) {
703
- let index = 0;
704
- return str.replace(/%s/g, () => {
705
- const arg = args[index++];
706
- return arg !== undefined ? arg : "";
707
- });
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
+ }
805
+ }
806
+ return false;
708
807
  }
709
- static getSafeRegistrationIdEnvName(authName) {
710
- if (!authName) {
711
- return "";
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;
712
841
  }
713
- let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
714
- if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
715
- safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
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}`);
716
1029
  }
717
- return safeRegistrationIdEnvName;
718
1030
  }
719
1031
  }
720
1032
 
@@ -734,7 +1046,14 @@ class SpecParser {
734
1046
  allowSwagger: false,
735
1047
  allowAPIKeyAuth: false,
736
1048
  allowMultipleParameters: false,
1049
+ allowBearerTokenAuth: false,
737
1050
  allowOauth2: false,
1051
+ allowMethods: ["get", "post"],
1052
+ allowConversationStarters: false,
1053
+ allowResponseSemantics: false,
1054
+ allowConfirmation: false,
1055
+ projectType: ProjectType.SME,
1056
+ isGptPlugin: false,
738
1057
  };
739
1058
  this.pathOrSpec = pathOrDoc;
740
1059
  this.parser = new SwaggerParser();
@@ -749,11 +1068,7 @@ class SpecParser {
749
1068
  try {
750
1069
  try {
751
1070
  await this.loadSpec();
752
- await this.parser.validate(this.spec, {
753
- validate: {
754
- schema: false,
755
- },
756
- });
1071
+ await this.parser.validate(this.spec);
757
1072
  }
758
1073
  catch (e) {
759
1074
  return {
@@ -762,16 +1077,46 @@ class SpecParser {
762
1077
  errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
763
1078
  };
764
1079
  }
1080
+ const errors = [];
1081
+ const warnings = [];
765
1082
  if (!this.options.allowSwagger && this.isSwaggerFile) {
766
1083
  return {
767
1084
  status: ValidationStatus.Error,
768
1085
  warnings: [],
769
1086
  errors: [
770
- { type: ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1087
+ {
1088
+ type: ErrorType.SwaggerNotSupported,
1089
+ content: ConstantString.SwaggerNotSupported,
1090
+ },
771
1091
  ],
772
1092
  };
773
1093
  }
774
- return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
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
+ };
775
1120
  }
776
1121
  catch (err) {
777
1122
  throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
@@ -780,17 +1125,20 @@ class SpecParser {
780
1125
  async listSupportedAPIInfo() {
781
1126
  try {
782
1127
  await this.loadSpec();
783
- const apiMap = this.getAllSupportedAPIs(this.spec);
1128
+ const apiMap = this.getAPIs(this.spec);
784
1129
  const apiInfos = [];
785
1130
  for (const key in apiMap) {
786
- const pathObjectItem = apiMap[key];
1131
+ const { operation, isValid } = apiMap[key];
1132
+ if (!isValid) {
1133
+ continue;
1134
+ }
787
1135
  const [method, path] = key.split(" ");
788
- const operationId = pathObjectItem.operationId;
1136
+ const operationId = operation.operationId;
789
1137
  // In Browser environment, this api is by default not support api without operationId
790
1138
  if (!operationId) {
791
1139
  continue;
792
1140
  }
793
- const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options.allowMultipleParameters);
1141
+ const command = Utils.parseApiInfo(operation, this.options);
794
1142
  const apiInfo = {
795
1143
  method: method,
796
1144
  path: path,
@@ -799,9 +1147,6 @@ class SpecParser {
799
1147
  parameters: command.parameters,
800
1148
  description: command.description,
801
1149
  };
802
- if (warning) {
803
- apiInfo.warning = warning;
804
- }
805
1150
  apiInfos.push(apiInfo);
806
1151
  }
807
1152
  return apiInfos;
@@ -827,6 +1172,17 @@ class SpecParser {
827
1172
  async getFilteredSpecs(filter, signal) {
828
1173
  throw new Error("Method not implemented.");
829
1174
  }
1175
+ /**
1176
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1177
+ * @param manifestPath A file path of the Teams app manifest file to update.
1178
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1179
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1180
+ * @param pluginFilePath File path of the api plugin file to generate.
1181
+ */
1182
+ // eslint-disable-next-line @typescript-eslint/require-await
1183
+ async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
1184
+ throw new Error("Method not implemented.");
1185
+ }
830
1186
  /**
831
1187
  * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
832
1188
  * @param manifestPath A file path of the Teams app manifest file to update.
@@ -836,7 +1192,7 @@ class SpecParser {
836
1192
  * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
837
1193
  */
838
1194
  // eslint-disable-next-line @typescript-eslint/require-await
839
- async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal, isMe) {
1195
+ async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
840
1196
  throw new Error("Method not implemented.");
841
1197
  }
842
1198
  async loadSpec() {
@@ -849,13 +1205,18 @@ class SpecParser {
849
1205
  this.spec = (await this.parser.dereference(clonedUnResolveSpec));
850
1206
  }
851
1207
  }
852
- getAllSupportedAPIs(spec) {
853
- if (this.apiMap !== undefined) {
854
- 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;
855
1216
  }
856
- const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
857
- this.apiMap = result;
858
- return result;
1217
+ const validator = ValidatorFactory.create(spec, this.options);
1218
+ this.validator = validator;
1219
+ return validator;
859
1220
  }
860
1221
  }
861
1222
 
@@ -863,7 +1224,7 @@ class SpecParser {
863
1224
  class AdaptiveCardGenerator {
864
1225
  static generateAdaptiveCard(operationItem) {
865
1226
  try {
866
- const json = Utils.getResponseJson(operationItem);
1227
+ const { json } = Utils.getResponseJson(operationItem);
867
1228
  let cardBody = [];
868
1229
  let schema = json.schema;
869
1230
  let jsonPath = "$";