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