@microsoft/m365-spec-parser 0.0.2-alpha.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.
@@ -0,0 +1,1372 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var SwaggerParser = require('@apidevtools/swagger-parser');
6
+ var converter = require('swagger2openapi');
7
+ var jsyaml = require('js-yaml');
8
+ var fs = require('fs-extra');
9
+ var path = require('path');
10
+
11
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
+
13
+ var SwaggerParser__default = /*#__PURE__*/_interopDefaultLegacy(SwaggerParser);
14
+ var converter__default = /*#__PURE__*/_interopDefaultLegacy(converter);
15
+ var jsyaml__default = /*#__PURE__*/_interopDefaultLegacy(jsyaml);
16
+ var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
17
+ var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
18
+
19
+ /******************************************************************************
20
+ Copyright (c) Microsoft Corporation.
21
+
22
+ Permission to use, copy, modify, and/or distribute this software for any
23
+ purpose with or without fee is hereby granted.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
26
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
27
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
28
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
29
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
30
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
31
+ PERFORMANCE OF THIS SOFTWARE.
32
+ ***************************************************************************** */
33
+
34
+ function __awaiter(thisArg, _arguments, P, generator) {
35
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
36
+ return new (P || (P = Promise))(function (resolve, reject) {
37
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
38
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
39
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
40
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
41
+ });
42
+ }
43
+
44
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
45
+ var e = new Error(message);
46
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
47
+ };
48
+
49
+ // Copyright (c) Microsoft Corporation.
50
+ /**
51
+ * An enum that represents the types of errors that can occur during validation.
52
+ */
53
+ exports.ErrorType = void 0;
54
+ (function (ErrorType) {
55
+ ErrorType["SpecNotValid"] = "spec-not-valid";
56
+ ErrorType["RemoteRefNotSupported"] = "remote-ref-not-supported";
57
+ ErrorType["NoServerInformation"] = "no-server-information";
58
+ ErrorType["UrlProtocolNotSupported"] = "url-protocol-not-supported";
59
+ ErrorType["RelativeServerUrlNotSupported"] = "relative-server-url-not-supported";
60
+ ErrorType["NoSupportedApi"] = "no-supported-api";
61
+ ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
62
+ ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
63
+ ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
64
+ ErrorType["MultipleAPIKeyNotSupported"] = "multiple-api-key-not-supported";
65
+ ErrorType["ListFailed"] = "list-failed";
66
+ ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
67
+ ErrorType["FilterSpecFailed"] = "filter-spec-failed";
68
+ ErrorType["UpdateManifestFailed"] = "update-manifest-failed";
69
+ ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
70
+ ErrorType["GenerateFailed"] = "generate-failed";
71
+ ErrorType["ValidateFailed"] = "validate-failed";
72
+ ErrorType["Cancelled"] = "cancelled";
73
+ ErrorType["Unknown"] = "unknown";
74
+ })(exports.ErrorType || (exports.ErrorType = {}));
75
+ /**
76
+ * An enum that represents the types of warnings that can occur during validation.
77
+ */
78
+ exports.WarningType = void 0;
79
+ (function (WarningType) {
80
+ WarningType["OperationIdMissing"] = "operationid-missing";
81
+ WarningType["GenerateCardFailed"] = "generate-card-failed";
82
+ WarningType["OperationOnlyContainsOptionalParam"] = "operation-only-contains-optional-param";
83
+ WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
84
+ WarningType["Unknown"] = "unknown";
85
+ })(exports.WarningType || (exports.WarningType = {}));
86
+ /**
87
+ * An enum that represents the validation status of an OpenAPI specification file.
88
+ */
89
+ exports.ValidationStatus = void 0;
90
+ (function (ValidationStatus) {
91
+ ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
92
+ ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
93
+ ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
94
+ })(exports.ValidationStatus || (exports.ValidationStatus = {}));
95
+
96
+ // Copyright (c) Microsoft Corporation.
97
+ class ConstantString {
98
+ }
99
+ ConstantString.CancelledMessage = "Operation is cancelled.";
100
+ ConstantString.NoServerInformation = "No server information is found in the OpenAPI description document.";
101
+ ConstantString.RemoteRefNotSupported = "Remote reference is not supported: %s.";
102
+ ConstantString.MissingOperationId = "Missing operationIds: %s.";
103
+ 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.";
104
+ ConstantString.AdditionalPropertiesNotSupported = "'additionalProperties' is not supported, and will be ignored.";
105
+ ConstantString.SchemaNotSupported = "'oneOf', 'anyOf', and 'not' schema are not supported: %s.";
106
+ ConstantString.UnknownSchema = "Unknown schema: %s.";
107
+ ConstantString.UrlProtocolNotSupported = "Server url is not correct: protocol %s is not supported, you should use https protocol instead.";
108
+ ConstantString.RelativeServerUrlNotSupported = "Server url is not correct: relative server url is not supported.";
109
+ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: please make sure that the environment variable %s is defined.";
110
+ ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
111
+ ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
112
+ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
113
+ ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
114
+ ConstantString.WrappedCardVersion = "devPreview";
115
+ ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
116
+ ConstantString.WrappedCardResponseLayout = "list";
117
+ ConstantString.GetMethod = "get";
118
+ ConstantString.PostMethod = "post";
119
+ ConstantString.AdaptiveCardVersion = "1.5";
120
+ ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
121
+ ConstantString.AdaptiveCardType = "AdaptiveCard";
122
+ ConstantString.TextBlockType = "TextBlock";
123
+ ConstantString.ContainerType = "Container";
124
+ ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
125
+ ConstantString.ResponseCodeFor20X = [
126
+ "200",
127
+ "201",
128
+ "202",
129
+ "203",
130
+ "204",
131
+ "205",
132
+ "206",
133
+ "207",
134
+ "208",
135
+ "226",
136
+ "default",
137
+ ];
138
+ ConstantString.AllOperationMethods = [
139
+ "get",
140
+ "post",
141
+ "put",
142
+ "delete",
143
+ "patch",
144
+ "head",
145
+ "options",
146
+ "trace",
147
+ ];
148
+ // TODO: update after investigating the usage of these constants.
149
+ ConstantString.WellknownResultNames = [
150
+ "result",
151
+ "data",
152
+ "items",
153
+ "root",
154
+ "matches",
155
+ "queries",
156
+ "list",
157
+ "output",
158
+ ];
159
+ ConstantString.WellknownTitleName = ["title", "name", "summary", "caption", "subject", "label"];
160
+ ConstantString.WellknownSubtitleName = [
161
+ "subtitle",
162
+ "id",
163
+ "uid",
164
+ "description",
165
+ "desc",
166
+ "detail",
167
+ ];
168
+ ConstantString.WellknownImageName = [
169
+ "image",
170
+ "icon",
171
+ "avatar",
172
+ "picture",
173
+ "photo",
174
+ "logo",
175
+ "pic",
176
+ "thumbnail",
177
+ "img",
178
+ ];
179
+ ConstantString.ShortDescriptionMaxLens = 80;
180
+ ConstantString.FullDescriptionMaxLens = 4000;
181
+ ConstantString.CommandDescriptionMaxLens = 128;
182
+ ConstantString.ParameterDescriptionMaxLens = 128;
183
+ ConstantString.CommandTitleMaxLens = 32;
184
+ ConstantString.ParameterTitleMaxLens = 32;
185
+
186
+ // Copyright (c) Microsoft Corporation.
187
+ class SpecParserError extends Error {
188
+ constructor(message, errorType) {
189
+ super(message);
190
+ this.errorType = errorType;
191
+ }
192
+ }
193
+
194
+ // Copyright (c) Microsoft Corporation.
195
+ class Utils {
196
+ static checkParameters(paramObject) {
197
+ const paramResult = {
198
+ requiredNum: 0,
199
+ optionalNum: 0,
200
+ isValid: true,
201
+ };
202
+ if (!paramObject) {
203
+ return paramResult;
204
+ }
205
+ for (let i = 0; i < paramObject.length; i++) {
206
+ const param = paramObject[i];
207
+ const schema = param.schema;
208
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
209
+ if (param.in === "header" || param.in === "cookie") {
210
+ if (isRequiredWithoutDefault) {
211
+ paramResult.isValid = false;
212
+ }
213
+ continue;
214
+ }
215
+ if (schema.type !== "boolean" &&
216
+ schema.type !== "string" &&
217
+ schema.type !== "number" &&
218
+ schema.type !== "integer") {
219
+ if (isRequiredWithoutDefault) {
220
+ paramResult.isValid = false;
221
+ }
222
+ continue;
223
+ }
224
+ if (param.in === "query" || param.in === "path") {
225
+ if (isRequiredWithoutDefault) {
226
+ paramResult.requiredNum = paramResult.requiredNum + 1;
227
+ }
228
+ else {
229
+ paramResult.optionalNum = paramResult.optionalNum + 1;
230
+ }
231
+ }
232
+ }
233
+ return paramResult;
234
+ }
235
+ static checkPostBody(schema, isRequired = false) {
236
+ var _a;
237
+ const paramResult = {
238
+ requiredNum: 0,
239
+ optionalNum: 0,
240
+ isValid: true,
241
+ };
242
+ if (Object.keys(schema).length === 0) {
243
+ return paramResult;
244
+ }
245
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
246
+ if (schema.type === "string" ||
247
+ schema.type === "integer" ||
248
+ schema.type === "boolean" ||
249
+ schema.type === "number") {
250
+ if (isRequiredWithoutDefault) {
251
+ paramResult.requiredNum = paramResult.requiredNum + 1;
252
+ }
253
+ else {
254
+ paramResult.optionalNum = paramResult.optionalNum + 1;
255
+ }
256
+ }
257
+ else if (schema.type === "object") {
258
+ const { properties } = schema;
259
+ for (const property in properties) {
260
+ let isRequired = false;
261
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
262
+ isRequired = true;
263
+ }
264
+ const result = Utils.checkPostBody(properties[property], isRequired);
265
+ paramResult.requiredNum += result.requiredNum;
266
+ paramResult.optionalNum += result.optionalNum;
267
+ paramResult.isValid = paramResult.isValid && result.isValid;
268
+ }
269
+ }
270
+ else {
271
+ if (isRequiredWithoutDefault) {
272
+ paramResult.isValid = false;
273
+ }
274
+ }
275
+ return paramResult;
276
+ }
277
+ /**
278
+ * Checks if the given API is supported.
279
+ * @param {string} method - The HTTP method of the API.
280
+ * @param {string} path - The path of the API.
281
+ * @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
282
+ * @returns {boolean} - Returns true if the API is supported, false otherwise.
283
+ * @description The following APIs are supported:
284
+ * 1. only support Get/Post operation without auth property
285
+ * 2. parameter inside query or path only support string, number, boolean and integer
286
+ * 3. parameter inside post body only support string, number, boolean, integer and object
287
+ * 4. request body + required parameters <= 1
288
+ * 5. response body should be “application/json” and not empty, and response code should be 20X
289
+ * 6. only support request body with “application/json” content type
290
+ */
291
+ static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
292
+ const pathObj = spec.paths[path];
293
+ method = method.toLocaleLowerCase();
294
+ if (pathObj) {
295
+ if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
296
+ pathObj[method]) {
297
+ const securities = pathObj[method].security;
298
+ const authArray = Utils.getAuthArray(securities, spec);
299
+ if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
300
+ return false;
301
+ }
302
+ const operationObject = pathObj[method];
303
+ if (!allowMissingId && !operationObject.operationId) {
304
+ return false;
305
+ }
306
+ const paramObject = operationObject.parameters;
307
+ const requestBody = operationObject.requestBody;
308
+ const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
309
+ const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
310
+ if (mediaTypesCount > 1) {
311
+ return false;
312
+ }
313
+ const responseJson = Utils.getResponseJson(operationObject);
314
+ if (Object.keys(responseJson).length === 0) {
315
+ return false;
316
+ }
317
+ let requestBodyParamResult = {
318
+ requiredNum: 0,
319
+ optionalNum: 0,
320
+ isValid: true,
321
+ };
322
+ if (requestJsonBody) {
323
+ const requestBodySchema = requestJsonBody.schema;
324
+ requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
325
+ }
326
+ if (!requestBodyParamResult.isValid) {
327
+ return false;
328
+ }
329
+ const paramResult = Utils.checkParameters(paramObject);
330
+ if (!paramResult.isValid) {
331
+ return false;
332
+ }
333
+ if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
334
+ if (allowMultipleParameters &&
335
+ requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
336
+ return true;
337
+ }
338
+ return false;
339
+ }
340
+ else if (requestBodyParamResult.requiredNum +
341
+ requestBodyParamResult.optionalNum +
342
+ paramResult.requiredNum +
343
+ paramResult.optionalNum ===
344
+ 0) {
345
+ return false;
346
+ }
347
+ else {
348
+ return true;
349
+ }
350
+ }
351
+ }
352
+ return false;
353
+ }
354
+ static isSupportedAuth(authSchemaArray, allowAPIKeyAuth, allowOauth2) {
355
+ if (authSchemaArray.length === 0) {
356
+ return true;
357
+ }
358
+ if (allowAPIKeyAuth || allowOauth2) {
359
+ // Currently we don't support multiple auth in one operation
360
+ if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
361
+ return false;
362
+ }
363
+ for (const auths of authSchemaArray) {
364
+ if (auths.length === 1) {
365
+ if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
366
+ return true;
367
+ }
368
+ else if (!allowAPIKeyAuth && allowOauth2 && Utils.isBearerTokenAuth(auths[0].authSchema)) {
369
+ return true;
370
+ }
371
+ else if (allowAPIKeyAuth &&
372
+ allowOauth2 &&
373
+ (Utils.isAPIKeyAuth(auths[0].authSchema) || Utils.isBearerTokenAuth(auths[0].authSchema))) {
374
+ return true;
375
+ }
376
+ }
377
+ }
378
+ }
379
+ return false;
380
+ }
381
+ static isAPIKeyAuth(authSchema) {
382
+ return authSchema.type === "apiKey";
383
+ }
384
+ static isBearerTokenAuth(authSchema) {
385
+ return (authSchema.type === "oauth2" ||
386
+ authSchema.type === "openIdConnect" ||
387
+ (authSchema.type === "http" && authSchema.scheme === "bearer"));
388
+ }
389
+ static getAuthArray(securities, spec) {
390
+ var _a;
391
+ const result = [];
392
+ const securitySchemas = (_a = spec.components) === null || _a === void 0 ? void 0 : _a.securitySchemes;
393
+ if (securities && securitySchemas) {
394
+ for (let i = 0; i < securities.length; i++) {
395
+ const security = securities[i];
396
+ const authArray = [];
397
+ for (const name in security) {
398
+ const auth = securitySchemas[name];
399
+ authArray.push({
400
+ authSchema: auth,
401
+ name: name,
402
+ });
403
+ }
404
+ if (authArray.length > 0) {
405
+ result.push(authArray);
406
+ }
407
+ }
408
+ }
409
+ result.sort((a, b) => a[0].name.localeCompare(b[0].name));
410
+ return result;
411
+ }
412
+ static updateFirstLetter(str) {
413
+ return str.charAt(0).toUpperCase() + str.slice(1);
414
+ }
415
+ static getResponseJson(operationObject) {
416
+ var _a, _b;
417
+ let json = {};
418
+ for (const code of ConstantString.ResponseCodeFor20X) {
419
+ const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
420
+ const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
421
+ if (mediaTypesCount > 1) {
422
+ return {};
423
+ }
424
+ if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
425
+ json = responseObject.content["application/json"];
426
+ break;
427
+ }
428
+ }
429
+ return json;
430
+ }
431
+ static convertPathToCamelCase(path) {
432
+ const pathSegments = path.split(/[./{]/);
433
+ const camelCaseSegments = pathSegments.map((segment) => {
434
+ segment = segment.replace(/}/g, "");
435
+ return segment.charAt(0).toUpperCase() + segment.slice(1);
436
+ });
437
+ const camelCasePath = camelCaseSegments.join("");
438
+ return camelCasePath;
439
+ }
440
+ static getUrlProtocol(urlString) {
441
+ try {
442
+ const url = new URL(urlString);
443
+ return url.protocol;
444
+ }
445
+ catch (err) {
446
+ return undefined;
447
+ }
448
+ }
449
+ static resolveServerUrl(url) {
450
+ const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
451
+ let matches = placeHolderReg.exec(url);
452
+ let newUrl = url;
453
+ while (matches != null) {
454
+ const envVar = matches[1];
455
+ const envVal = process.env[envVar];
456
+ if (!envVal) {
457
+ throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
458
+ }
459
+ else {
460
+ newUrl = newUrl.replace(matches[0], envVal);
461
+ }
462
+ matches = placeHolderReg.exec(url);
463
+ }
464
+ return newUrl;
465
+ }
466
+ static checkServerUrl(servers) {
467
+ const errors = [];
468
+ let serverUrl;
469
+ try {
470
+ serverUrl = Utils.resolveServerUrl(servers[0].url);
471
+ }
472
+ catch (err) {
473
+ errors.push({
474
+ type: exports.ErrorType.ResolveServerUrlFailed,
475
+ content: err.message,
476
+ data: servers,
477
+ });
478
+ return errors;
479
+ }
480
+ const protocol = Utils.getUrlProtocol(serverUrl);
481
+ if (!protocol) {
482
+ // Relative server url is not supported
483
+ errors.push({
484
+ type: exports.ErrorType.RelativeServerUrlNotSupported,
485
+ content: ConstantString.RelativeServerUrlNotSupported,
486
+ data: servers,
487
+ });
488
+ }
489
+ else if (protocol !== "https:") {
490
+ // Http server url is not supported
491
+ const protocolString = protocol.slice(0, -1);
492
+ errors.push({
493
+ type: exports.ErrorType.UrlProtocolNotSupported,
494
+ content: Utils.format(ConstantString.UrlProtocolNotSupported, protocol.slice(0, -1)),
495
+ data: protocolString,
496
+ });
497
+ }
498
+ return errors;
499
+ }
500
+ static validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
501
+ const errors = [];
502
+ let hasTopLevelServers = false;
503
+ let hasPathLevelServers = false;
504
+ let hasOperationLevelServers = false;
505
+ if (spec.servers && spec.servers.length >= 1) {
506
+ hasTopLevelServers = true;
507
+ // for multiple server, we only use the first url
508
+ const serverErrors = Utils.checkServerUrl(spec.servers);
509
+ errors.push(...serverErrors);
510
+ }
511
+ const paths = spec.paths;
512
+ for (const path in paths) {
513
+ const methods = paths[path];
514
+ if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
515
+ hasPathLevelServers = true;
516
+ const serverErrors = Utils.checkServerUrl(methods.servers);
517
+ errors.push(...serverErrors);
518
+ }
519
+ for (const method in methods) {
520
+ const operationObject = methods[method];
521
+ if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
522
+ if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
523
+ hasOperationLevelServers = true;
524
+ const serverErrors = Utils.checkServerUrl(operationObject.servers);
525
+ errors.push(...serverErrors);
526
+ }
527
+ }
528
+ }
529
+ }
530
+ if (!hasTopLevelServers && !hasPathLevelServers && !hasOperationLevelServers) {
531
+ errors.push({
532
+ type: exports.ErrorType.NoServerInformation,
533
+ content: ConstantString.NoServerInformation,
534
+ });
535
+ }
536
+ return errors;
537
+ }
538
+ static isWellKnownName(name, wellknownNameList) {
539
+ for (let i = 0; i < wellknownNameList.length; i++) {
540
+ name = name.replace(/_/g, "").replace(/-/g, "");
541
+ if (name.toLowerCase().includes(wellknownNameList[i])) {
542
+ return true;
543
+ }
544
+ }
545
+ return false;
546
+ }
547
+ static generateParametersFromSchema(schema, name, allowMultipleParameters, isRequired = false) {
548
+ var _a, _b;
549
+ const requiredParams = [];
550
+ const optionalParams = [];
551
+ if (schema.type === "string" ||
552
+ schema.type === "integer" ||
553
+ schema.type === "boolean" ||
554
+ schema.type === "number") {
555
+ const parameter = {
556
+ name: name,
557
+ title: Utils.updateFirstLetter(name).slice(0, ConstantString.ParameterTitleMaxLens),
558
+ description: ((_a = schema.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
559
+ };
560
+ if (allowMultipleParameters) {
561
+ Utils.updateParameterWithInputType(schema, parameter);
562
+ }
563
+ if (isRequired && schema.default === undefined) {
564
+ requiredParams.push(parameter);
565
+ }
566
+ else {
567
+ optionalParams.push(parameter);
568
+ }
569
+ }
570
+ else if (schema.type === "object") {
571
+ const { properties } = schema;
572
+ for (const property in properties) {
573
+ let isRequired = false;
574
+ if (schema.required && ((_b = schema.required) === null || _b === void 0 ? void 0 : _b.indexOf(property)) >= 0) {
575
+ isRequired = true;
576
+ }
577
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(properties[property], property, allowMultipleParameters, isRequired);
578
+ requiredParams.push(...requiredP);
579
+ optionalParams.push(...optionalP);
580
+ }
581
+ }
582
+ return [requiredParams, optionalParams];
583
+ }
584
+ static updateParameterWithInputType(schema, param) {
585
+ if (schema.enum) {
586
+ param.inputType = "choiceset";
587
+ param.choices = [];
588
+ for (let i = 0; i < schema.enum.length; i++) {
589
+ param.choices.push({
590
+ title: schema.enum[i],
591
+ value: schema.enum[i],
592
+ });
593
+ }
594
+ }
595
+ else if (schema.type === "string") {
596
+ param.inputType = "text";
597
+ }
598
+ else if (schema.type === "integer" || schema.type === "number") {
599
+ param.inputType = "number";
600
+ }
601
+ else if (schema.type === "boolean") {
602
+ param.inputType = "toggle";
603
+ }
604
+ if (schema.default) {
605
+ param.value = schema.default;
606
+ }
607
+ }
608
+ static parseApiInfo(operationItem, allowMultipleParameters) {
609
+ var _a, _b;
610
+ const requiredParams = [];
611
+ const optionalParams = [];
612
+ const paramObject = operationItem.parameters;
613
+ if (paramObject) {
614
+ paramObject.forEach((param) => {
615
+ var _a;
616
+ const parameter = {
617
+ name: param.name,
618
+ title: Utils.updateFirstLetter(param.name).slice(0, ConstantString.ParameterTitleMaxLens),
619
+ description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
620
+ };
621
+ const schema = param.schema;
622
+ if (allowMultipleParameters && schema) {
623
+ Utils.updateParameterWithInputType(schema, parameter);
624
+ }
625
+ if (param.in !== "header" && param.in !== "cookie") {
626
+ if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
627
+ requiredParams.push(parameter);
628
+ }
629
+ else {
630
+ optionalParams.push(parameter);
631
+ }
632
+ }
633
+ });
634
+ }
635
+ if (operationItem.requestBody) {
636
+ const requestBody = operationItem.requestBody;
637
+ const requestJson = requestBody.content["application/json"];
638
+ if (Object.keys(requestJson).length !== 0) {
639
+ const schema = requestJson.schema;
640
+ const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
641
+ requiredParams.push(...requiredP);
642
+ optionalParams.push(...optionalP);
643
+ }
644
+ }
645
+ const operationId = operationItem.operationId;
646
+ const parameters = [];
647
+ if (requiredParams.length !== 0) {
648
+ parameters.push(...requiredParams);
649
+ }
650
+ else {
651
+ parameters.push(optionalParams[0]);
652
+ }
653
+ const command = {
654
+ context: ["compose"],
655
+ type: "query",
656
+ title: ((_a = operationItem.summary) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.CommandTitleMaxLens),
657
+ id: operationId,
658
+ parameters: parameters,
659
+ description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
660
+ };
661
+ let warning = undefined;
662
+ if (requiredParams.length === 0 && optionalParams.length > 1) {
663
+ warning = {
664
+ type: exports.WarningType.OperationOnlyContainsOptionalParam,
665
+ content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, operationId),
666
+ data: operationId,
667
+ };
668
+ }
669
+ return [command, warning];
670
+ }
671
+ static listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
672
+ const paths = spec.paths;
673
+ const result = {};
674
+ for (const path in paths) {
675
+ const methods = paths[path];
676
+ for (const method in methods) {
677
+ // For developer preview, only support GET operation with only 1 parameter without auth
678
+ if (Utils.isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
679
+ const operationObject = methods[method];
680
+ result[`${method.toUpperCase()} ${path}`] = operationObject;
681
+ }
682
+ }
683
+ }
684
+ return result;
685
+ }
686
+ static validateSpec(spec, parser, isSwaggerFile, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
687
+ const errors = [];
688
+ const warnings = [];
689
+ if (isSwaggerFile) {
690
+ warnings.push({
691
+ type: exports.WarningType.ConvertSwaggerToOpenAPI,
692
+ content: ConstantString.ConvertSwaggerToOpenAPI,
693
+ });
694
+ }
695
+ // Server validation
696
+ const serverErrors = Utils.validateServer(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
697
+ errors.push(...serverErrors);
698
+ // Remote reference not supported
699
+ const refPaths = parser.$refs.paths();
700
+ // refPaths [0] is the current spec file path
701
+ if (refPaths.length > 1) {
702
+ errors.push({
703
+ type: exports.ErrorType.RemoteRefNotSupported,
704
+ content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
705
+ data: refPaths,
706
+ });
707
+ }
708
+ // No supported API
709
+ const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
710
+ if (Object.keys(apiMap).length === 0) {
711
+ errors.push({
712
+ type: exports.ErrorType.NoSupportedApi,
713
+ content: ConstantString.NoSupportedApi,
714
+ });
715
+ }
716
+ // OperationId missing
717
+ const apisMissingOperationId = [];
718
+ for (const key in apiMap) {
719
+ const pathObjectItem = apiMap[key];
720
+ if (!pathObjectItem.operationId) {
721
+ apisMissingOperationId.push(key);
722
+ }
723
+ }
724
+ if (apisMissingOperationId.length > 0) {
725
+ warnings.push({
726
+ type: exports.WarningType.OperationIdMissing,
727
+ content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
728
+ data: apisMissingOperationId,
729
+ });
730
+ }
731
+ let status = exports.ValidationStatus.Valid;
732
+ if (warnings.length > 0 && errors.length === 0) {
733
+ status = exports.ValidationStatus.Warning;
734
+ }
735
+ else if (errors.length > 0) {
736
+ status = exports.ValidationStatus.Error;
737
+ }
738
+ return {
739
+ status,
740
+ warnings,
741
+ errors,
742
+ };
743
+ }
744
+ static format(str, ...args) {
745
+ let index = 0;
746
+ return str.replace(/%s/g, () => {
747
+ const arg = args[index++];
748
+ return arg !== undefined ? arg : "";
749
+ });
750
+ }
751
+ static getSafeRegistrationIdEnvName(authName) {
752
+ if (!authName) {
753
+ return "";
754
+ }
755
+ let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
756
+ if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
757
+ safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
758
+ }
759
+ return safeRegistrationIdEnvName;
760
+ }
761
+ }
762
+
763
+ // Copyright (c) Microsoft Corporation.
764
+ class SpecFilter {
765
+ static specFilter(filter, unResolveSpec, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
766
+ try {
767
+ const newSpec = Object.assign({}, unResolveSpec);
768
+ const newPaths = {};
769
+ for (const filterItem of filter) {
770
+ const [method, path] = filterItem.split(" ");
771
+ const methodName = method.toLowerCase();
772
+ if (!Utils.isSupportedApi(methodName, path, resolvedSpec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2)) {
773
+ continue;
774
+ }
775
+ if (!newPaths[path]) {
776
+ newPaths[path] = Object.assign({}, unResolveSpec.paths[path]);
777
+ for (const m of ConstantString.AllOperationMethods) {
778
+ delete newPaths[path][m];
779
+ }
780
+ }
781
+ newPaths[path][methodName] = unResolveSpec.paths[path][methodName];
782
+ // Add the operationId if missing
783
+ if (!newPaths[path][methodName].operationId) {
784
+ newPaths[path][methodName].operationId = `${methodName}${Utils.convertPathToCamelCase(path)}`;
785
+ }
786
+ }
787
+ newSpec.paths = newPaths;
788
+ return newSpec;
789
+ }
790
+ catch (err) {
791
+ throw new SpecParserError(err.toString(), exports.ErrorType.FilterSpecFailed);
792
+ }
793
+ }
794
+ }
795
+
796
+ // Copyright (c) Microsoft Corporation.
797
+ class ManifestUpdater {
798
+ static updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, spec, allowMultipleParameters, auth) {
799
+ var _a, _b;
800
+ return __awaiter(this, void 0, void 0, function* () {
801
+ try {
802
+ const originalManifest = yield fs__default["default"].readJSON(manifestPath);
803
+ const updatedPart = {};
804
+ const [commands, warnings] = yield ManifestUpdater.generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters);
805
+ const composeExtension = {
806
+ composeExtensionType: "apiBased",
807
+ apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
808
+ commands: commands,
809
+ };
810
+ if (auth) {
811
+ if (Utils.isAPIKeyAuth(auth)) {
812
+ auth = auth;
813
+ const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${auth.name}_${ConstantString.RegistrationIdPostfix}`);
814
+ composeExtension.authorization = {
815
+ authType: "apiSecretServiceAuth",
816
+ apiSecretServiceAuthConfiguration: {
817
+ apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
818
+ },
819
+ };
820
+ }
821
+ else if (Utils.isBearerTokenAuth(auth)) {
822
+ composeExtension.authorization = {
823
+ authType: "microsoftEntra",
824
+ microsoftEntraConfiguration: {
825
+ supportsSingleSignOn: true,
826
+ },
827
+ };
828
+ updatedPart.webApplicationInfo = {
829
+ id: "${{AAD_APP_CLIENT_ID}}",
830
+ resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
831
+ };
832
+ }
833
+ }
834
+ updatedPart.description = {
835
+ short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
836
+ full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : originalManifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
837
+ };
838
+ updatedPart.composeExtensions = [composeExtension];
839
+ const updatedManifest = Object.assign(Object.assign({}, originalManifest), updatedPart);
840
+ return [updatedManifest, warnings];
841
+ }
842
+ catch (err) {
843
+ throw new SpecParserError(err.toString(), exports.ErrorType.UpdateManifestFailed);
844
+ }
845
+ });
846
+ }
847
+ static generateCommands(spec, adaptiveCardFolder, manifestPath, allowMultipleParameters) {
848
+ return __awaiter(this, void 0, void 0, function* () {
849
+ const paths = spec.paths;
850
+ const commands = [];
851
+ const warnings = [];
852
+ if (paths) {
853
+ for (const pathUrl in paths) {
854
+ const pathItem = paths[pathUrl];
855
+ if (pathItem) {
856
+ const operations = pathItem;
857
+ // Currently only support GET and POST method
858
+ for (const method in operations) {
859
+ if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
860
+ const operationItem = operations[method];
861
+ if (operationItem) {
862
+ const [command, warning] = Utils.parseApiInfo(operationItem, allowMultipleParameters);
863
+ const adaptiveCardPath = path__default["default"].join(adaptiveCardFolder, command.id + ".json");
864
+ command.apiResponseRenderingTemplateFile = (yield fs__default["default"].pathExists(adaptiveCardPath))
865
+ ? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
866
+ : "";
867
+ if (warning) {
868
+ warnings.push(warning);
869
+ }
870
+ commands.push(command);
871
+ }
872
+ }
873
+ }
874
+ }
875
+ }
876
+ }
877
+ return [commands, warnings];
878
+ });
879
+ }
880
+ static getRelativePath(from, to) {
881
+ const relativePath = path__default["default"].relative(path__default["default"].dirname(from), to);
882
+ return path__default["default"].normalize(relativePath).replace(/\\/g, "/");
883
+ }
884
+ }
885
+
886
+ // Copyright (c) Microsoft Corporation.
887
+ class AdaptiveCardGenerator {
888
+ static generateAdaptiveCard(operationItem) {
889
+ try {
890
+ const json = Utils.getResponseJson(operationItem);
891
+ let cardBody = [];
892
+ let schema = json.schema;
893
+ let jsonPath = "$";
894
+ if (schema && Object.keys(schema).length > 0) {
895
+ jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
896
+ if (jsonPath !== "$") {
897
+ schema = schema.properties[jsonPath];
898
+ }
899
+ cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
900
+ }
901
+ // if no schema, try to use example value
902
+ if (cardBody.length === 0 && (json.examples || json.example)) {
903
+ cardBody = [
904
+ {
905
+ type: ConstantString.TextBlockType,
906
+ text: "${jsonStringify($root)}",
907
+ wrap: true,
908
+ },
909
+ ];
910
+ }
911
+ // if no example value, use default success response
912
+ if (cardBody.length === 0) {
913
+ cardBody = [
914
+ {
915
+ type: ConstantString.TextBlockType,
916
+ text: "success",
917
+ wrap: true,
918
+ },
919
+ ];
920
+ }
921
+ const fullCard = {
922
+ type: ConstantString.AdaptiveCardType,
923
+ $schema: ConstantString.AdaptiveCardSchema,
924
+ version: ConstantString.AdaptiveCardVersion,
925
+ body: cardBody,
926
+ };
927
+ return [fullCard, jsonPath];
928
+ }
929
+ catch (err) {
930
+ throw new SpecParserError(err.toString(), exports.ErrorType.GenerateAdaptiveCardFailed);
931
+ }
932
+ }
933
+ static generateCardFromResponse(schema, name, parentArrayName = "") {
934
+ if (schema.type === "array") {
935
+ // schema.items can be arbitrary object: schema { type: array, items: {} }
936
+ if (Object.keys(schema.items).length === 0) {
937
+ return [
938
+ {
939
+ type: ConstantString.TextBlockType,
940
+ text: name ? `${name}: \${jsonStringify(${name})}` : "result: ${jsonStringify($root)}",
941
+ wrap: true,
942
+ },
943
+ ];
944
+ }
945
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
946
+ const template = {
947
+ type: ConstantString.ContainerType,
948
+ $data: name ? `\${${name}}` : "${$root}",
949
+ items: Array(),
950
+ };
951
+ template.items.push(...obj);
952
+ return [template];
953
+ }
954
+ // some schema may not contain type but contain properties
955
+ if (schema.type === "object" || (!schema.type && schema.properties)) {
956
+ const { properties } = schema;
957
+ const result = [];
958
+ for (const property in properties) {
959
+ const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
960
+ result.push(...obj);
961
+ }
962
+ if (schema.additionalProperties) {
963
+ // TODO: better ways to handler warnings.
964
+ console.warn(ConstantString.AdditionalPropertiesNotSupported);
965
+ }
966
+ return result;
967
+ }
968
+ if (schema.type === "string" ||
969
+ schema.type === "integer" ||
970
+ schema.type === "boolean" ||
971
+ schema.type === "number") {
972
+ if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
973
+ // string in root: "ddd"
974
+ let text = "result: ${$root}";
975
+ if (name) {
976
+ // object { id: "1" }
977
+ text = `${name}: \${if(${name}, ${name}, 'N/A')}`;
978
+ if (parentArrayName) {
979
+ // object types inside array: { tags: ["id": 1, "name": "name"] }
980
+ text = `${parentArrayName}.${text}`;
981
+ }
982
+ }
983
+ else if (parentArrayName) {
984
+ // string array: photoUrls: ["1", "2"]
985
+ text = `${parentArrayName}: ` + "${$data}";
986
+ }
987
+ return [
988
+ {
989
+ type: ConstantString.TextBlockType,
990
+ text,
991
+ wrap: true,
992
+ },
993
+ ];
994
+ }
995
+ else {
996
+ if (name) {
997
+ return [
998
+ {
999
+ type: "Image",
1000
+ url: `\${${name}}`,
1001
+ $when: `\${${name} != null}`,
1002
+ },
1003
+ ];
1004
+ }
1005
+ else {
1006
+ return [
1007
+ {
1008
+ type: "Image",
1009
+ url: "${$data}",
1010
+ $when: "${$data != null}",
1011
+ },
1012
+ ];
1013
+ }
1014
+ }
1015
+ }
1016
+ if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
1017
+ throw new Error(Utils.format(ConstantString.SchemaNotSupported, JSON.stringify(schema)));
1018
+ }
1019
+ throw new Error(Utils.format(ConstantString.UnknownSchema, JSON.stringify(schema)));
1020
+ }
1021
+ // Find the first array property in the response schema object with the well-known name
1022
+ static getResponseJsonPathFromSchema(schema) {
1023
+ if (schema.type === "object" || (!schema.type && schema.properties)) {
1024
+ const { properties } = schema;
1025
+ for (const property in properties) {
1026
+ const schema = properties[property];
1027
+ if (schema.type === "array" &&
1028
+ Utils.isWellKnownName(property, ConstantString.WellknownResultNames)) {
1029
+ return property;
1030
+ }
1031
+ }
1032
+ }
1033
+ return "$";
1034
+ }
1035
+ static isImageUrlProperty(schema, name, parentArrayName) {
1036
+ const propertyName = name ? name : parentArrayName;
1037
+ return (!!propertyName &&
1038
+ schema.type === "string" &&
1039
+ Utils.isWellKnownName(propertyName, ConstantString.WellknownImageName) &&
1040
+ (propertyName.toLocaleLowerCase().indexOf("url") >= 0 || schema.format === "uri"));
1041
+ }
1042
+ }
1043
+
1044
+ // Copyright (c) Microsoft Corporation.
1045
+ function wrapAdaptiveCard(card, jsonPath) {
1046
+ const result = {
1047
+ version: ConstantString.WrappedCardVersion,
1048
+ $schema: ConstantString.WrappedCardSchema,
1049
+ jsonPath: jsonPath,
1050
+ responseLayout: ConstantString.WrappedCardResponseLayout,
1051
+ responseCardTemplate: card,
1052
+ previewCardTemplate: inferPreviewCardTemplate(card),
1053
+ };
1054
+ return result;
1055
+ }
1056
+ /**
1057
+ * Infers the preview card template from an Adaptive Card and a JSON path.
1058
+ * The preview card template includes a title and an optional subtitle and image.
1059
+ * It populates the preview card template with the first text block that matches
1060
+ * each well-known name, in the order of title, subtitle, and image.
1061
+ * If no text block matches the title or subtitle, it uses the first two text block as the title and subtitle.
1062
+ * If the title is still empty and the subtitle is not empty, it uses subtitle as the title.
1063
+ * @param card The Adaptive Card to infer the preview card template from.
1064
+ * @param jsonPath The JSON path to the root object in the card body.
1065
+ * @returns The inferred preview card template.
1066
+ */
1067
+ function inferPreviewCardTemplate(card) {
1068
+ var _a;
1069
+ const result = {
1070
+ title: "",
1071
+ };
1072
+ const textBlockElements = new Set();
1073
+ let rootObject;
1074
+ if (((_a = card.body[0]) === null || _a === void 0 ? void 0 : _a.type) === ConstantString.ContainerType) {
1075
+ rootObject = card.body[0].items;
1076
+ }
1077
+ else {
1078
+ rootObject = card.body;
1079
+ }
1080
+ for (const element of rootObject) {
1081
+ if (element.type === ConstantString.TextBlockType) {
1082
+ const textElement = element;
1083
+ const index = textElement.text.indexOf("${if(");
1084
+ if (index > 0) {
1085
+ textElement.text = textElement.text.substring(index);
1086
+ textBlockElements.add(textElement);
1087
+ }
1088
+ }
1089
+ }
1090
+ for (const element of textBlockElements) {
1091
+ const text = element.text;
1092
+ if (!result.title && Utils.isWellKnownName(text, ConstantString.WellknownTitleName)) {
1093
+ result.title = text;
1094
+ textBlockElements.delete(element);
1095
+ }
1096
+ else if (!result.subtitle && Utils.isWellKnownName(text, ConstantString.WellknownSubtitleName)) {
1097
+ result.subtitle = text;
1098
+ textBlockElements.delete(element);
1099
+ }
1100
+ else if (!result.image && Utils.isWellKnownName(text, ConstantString.WellknownImageName)) {
1101
+ const match = text.match(/\${if\(([^,]+),/);
1102
+ const property = match ? match[1] : "";
1103
+ if (property) {
1104
+ result.image = {
1105
+ url: `\${${property}}`,
1106
+ alt: text,
1107
+ $when: `\${${property} != null}`,
1108
+ };
1109
+ }
1110
+ textBlockElements.delete(element);
1111
+ }
1112
+ }
1113
+ for (const element of textBlockElements) {
1114
+ const text = element.text;
1115
+ if (!result.title) {
1116
+ result.title = text;
1117
+ textBlockElements.delete(element);
1118
+ }
1119
+ else if (!result.subtitle) {
1120
+ result.subtitle = text;
1121
+ textBlockElements.delete(element);
1122
+ }
1123
+ }
1124
+ if (!result.title && result.subtitle) {
1125
+ result.title = result.subtitle;
1126
+ delete result.subtitle;
1127
+ }
1128
+ if (!result.title) {
1129
+ result.title = "result";
1130
+ }
1131
+ return result;
1132
+ }
1133
+
1134
+ // Copyright (c) Microsoft Corporation.
1135
+ /**
1136
+ * A class that parses an OpenAPI specification file and provides methods to validate, list, and generate artifacts.
1137
+ */
1138
+ class SpecParser {
1139
+ /**
1140
+ * Creates a new instance of the SpecParser class.
1141
+ * @param pathOrDoc The path to the OpenAPI specification file or the OpenAPI specification object.
1142
+ * @param options The options for parsing the OpenAPI specification file.
1143
+ */
1144
+ constructor(pathOrDoc, options) {
1145
+ this.defaultOptions = {
1146
+ allowMissingId: true,
1147
+ allowSwagger: true,
1148
+ allowAPIKeyAuth: false,
1149
+ allowMultipleParameters: false,
1150
+ allowOauth2: false,
1151
+ };
1152
+ this.pathOrSpec = pathOrDoc;
1153
+ this.parser = new SwaggerParser__default["default"]();
1154
+ this.options = Object.assign(Object.assign({}, this.defaultOptions), (options !== null && options !== void 0 ? options : {}));
1155
+ }
1156
+ /**
1157
+ * Validates the OpenAPI specification file and returns a validation result.
1158
+ *
1159
+ * @returns A validation result object that contains information about any errors or warnings in the specification file.
1160
+ */
1161
+ validate() {
1162
+ return __awaiter(this, void 0, void 0, function* () {
1163
+ try {
1164
+ try {
1165
+ yield this.loadSpec();
1166
+ yield this.parser.validate(this.spec);
1167
+ }
1168
+ catch (e) {
1169
+ return {
1170
+ status: exports.ValidationStatus.Error,
1171
+ warnings: [],
1172
+ errors: [{ type: exports.ErrorType.SpecNotValid, content: e.toString() }],
1173
+ };
1174
+ }
1175
+ if (!this.options.allowSwagger && this.isSwaggerFile) {
1176
+ return {
1177
+ status: exports.ValidationStatus.Error,
1178
+ warnings: [],
1179
+ errors: [
1180
+ { type: exports.ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1181
+ ],
1182
+ };
1183
+ }
1184
+ return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1185
+ }
1186
+ catch (err) {
1187
+ throw new SpecParserError(err.toString(), exports.ErrorType.ValidateFailed);
1188
+ }
1189
+ });
1190
+ }
1191
+ // eslint-disable-next-line @typescript-eslint/require-await
1192
+ listSupportedAPIInfo() {
1193
+ return __awaiter(this, void 0, void 0, function* () {
1194
+ throw new Error("Method not implemented.");
1195
+ });
1196
+ }
1197
+ /**
1198
+ * Lists all the OpenAPI operations in the specification file.
1199
+ * @returns A string array that represents the HTTP method and path of each operation, such as ['GET /pets/{petId}', 'GET /user/{userId}']
1200
+ * according to copilot plugin spec, only list get and post method without auth
1201
+ */
1202
+ list() {
1203
+ var _a;
1204
+ return __awaiter(this, void 0, void 0, function* () {
1205
+ try {
1206
+ yield this.loadSpec();
1207
+ const spec = this.spec;
1208
+ const apiMap = this.getAllSupportedAPIs(spec);
1209
+ const result = [];
1210
+ for (const apiKey in apiMap) {
1211
+ const apiResult = {
1212
+ api: "",
1213
+ server: "",
1214
+ operationId: "",
1215
+ };
1216
+ const [method, path] = apiKey.split(" ");
1217
+ const operation = apiMap[apiKey];
1218
+ const rootServer = spec.servers && spec.servers[0];
1219
+ const methodServer = spec.paths[path].servers && ((_a = spec.paths[path]) === null || _a === void 0 ? void 0 : _a.servers[0]);
1220
+ const operationServer = operation.servers && operation.servers[0];
1221
+ const serverUrl = operationServer || methodServer || rootServer;
1222
+ if (!serverUrl) {
1223
+ throw new SpecParserError(ConstantString.NoServerInformation, exports.ErrorType.NoServerInformation);
1224
+ }
1225
+ apiResult.server = Utils.resolveServerUrl(serverUrl.url);
1226
+ let operationId = operation.operationId;
1227
+ if (!operationId) {
1228
+ operationId = `${method.toLowerCase()}${Utils.convertPathToCamelCase(path)}`;
1229
+ }
1230
+ apiResult.operationId = operationId;
1231
+ const authArray = Utils.getAuthArray(operation.security, spec);
1232
+ for (const auths of authArray) {
1233
+ if (auths.length === 1) {
1234
+ apiResult.auth = auths[0].authSchema;
1235
+ break;
1236
+ }
1237
+ }
1238
+ apiResult.api = apiKey;
1239
+ result.push(apiResult);
1240
+ }
1241
+ return result;
1242
+ }
1243
+ catch (err) {
1244
+ if (err instanceof SpecParserError) {
1245
+ throw err;
1246
+ }
1247
+ throw new SpecParserError(err.toString(), exports.ErrorType.ListFailed);
1248
+ }
1249
+ });
1250
+ }
1251
+ /**
1252
+ * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
1253
+ * @param manifestPath A file path of the Teams app manifest file to update.
1254
+ * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
1255
+ * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
1256
+ * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
1257
+ */
1258
+ generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
1259
+ return __awaiter(this, void 0, void 0, function* () {
1260
+ const result = {
1261
+ allSuccess: true,
1262
+ warnings: [],
1263
+ };
1264
+ try {
1265
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1266
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1267
+ }
1268
+ yield this.loadSpec();
1269
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1270
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1271
+ }
1272
+ const newUnResolvedSpec = SpecFilter.specFilter(filter, this.unResolveSpec, this.spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1273
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1274
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1275
+ }
1276
+ const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
1277
+ const AuthSet = new Set();
1278
+ let hasMultipleAPIKeyAuth = false;
1279
+ for (const url in newSpec.paths) {
1280
+ for (const method in newSpec.paths[url]) {
1281
+ const operation = newSpec.paths[url][method];
1282
+ const authArray = Utils.getAuthArray(operation.security, newSpec);
1283
+ if (authArray && authArray.length > 0) {
1284
+ AuthSet.add(authArray[0][0].authSchema);
1285
+ if (AuthSet.size > 1) {
1286
+ hasMultipleAPIKeyAuth = true;
1287
+ break;
1288
+ }
1289
+ }
1290
+ }
1291
+ }
1292
+ if (hasMultipleAPIKeyAuth) {
1293
+ throw new SpecParserError(ConstantString.MultipleAPIKeyNotSupported, exports.ErrorType.MultipleAPIKeyNotSupported);
1294
+ }
1295
+ let resultStr;
1296
+ if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1297
+ resultStr = jsyaml__default["default"].dump(newUnResolvedSpec);
1298
+ }
1299
+ else {
1300
+ resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1301
+ }
1302
+ yield fs__default["default"].outputFile(outputSpecPath, resultStr);
1303
+ for (const url in newSpec.paths) {
1304
+ for (const method in newSpec.paths[url]) {
1305
+ // paths object may contain description/summary, so we need to check if it is a operation object
1306
+ if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
1307
+ const operation = newSpec.paths[url][method];
1308
+ try {
1309
+ const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1310
+ const fileName = path__default["default"].join(adaptiveCardFolder, `${operation.operationId}.json`);
1311
+ const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1312
+ yield fs__default["default"].outputJSON(fileName, wrappedCard, { spaces: 2 });
1313
+ const dataFileName = path__default["default"].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
1314
+ yield fs__default["default"].outputJSON(dataFileName, {}, { spaces: 2 });
1315
+ }
1316
+ catch (err) {
1317
+ result.allSuccess = false;
1318
+ result.warnings.push({
1319
+ type: exports.WarningType.GenerateCardFailed,
1320
+ content: err.toString(),
1321
+ data: operation.operationId,
1322
+ });
1323
+ }
1324
+ }
1325
+ }
1326
+ }
1327
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1328
+ throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1329
+ }
1330
+ const auth = Array.from(AuthSet)[0];
1331
+ const [updatedManifest, warnings] = yield ManifestUpdater.updateManifest(manifestPath, outputSpecPath, adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, auth);
1332
+ yield fs__default["default"].outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1333
+ result.warnings.push(...warnings);
1334
+ }
1335
+ catch (err) {
1336
+ if (err instanceof SpecParserError) {
1337
+ throw err;
1338
+ }
1339
+ throw new SpecParserError(err.toString(), exports.ErrorType.GenerateFailed);
1340
+ }
1341
+ return result;
1342
+ });
1343
+ }
1344
+ loadSpec() {
1345
+ return __awaiter(this, void 0, void 0, function* () {
1346
+ if (!this.spec) {
1347
+ this.unResolveSpec = (yield this.parser.parse(this.pathOrSpec));
1348
+ // Convert swagger 2.0 to openapi 3.0
1349
+ if (!this.unResolveSpec.openapi && this.unResolveSpec.swagger === "2.0") {
1350
+ const specObj = yield converter__default["default"].convert(this.unResolveSpec, {});
1351
+ this.unResolveSpec = specObj.openapi;
1352
+ this.isSwaggerFile = true;
1353
+ }
1354
+ const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
1355
+ this.spec = (yield this.parser.dereference(clonedUnResolveSpec));
1356
+ }
1357
+ });
1358
+ }
1359
+ getAllSupportedAPIs(spec) {
1360
+ if (this.apiMap !== undefined) {
1361
+ return this.apiMap;
1362
+ }
1363
+ const result = Utils.listSupportedAPIs(spec, this.options.allowMissingId, this.options.allowAPIKeyAuth, this.options.allowMultipleParameters, this.options.allowOauth2);
1364
+ this.apiMap = result;
1365
+ return result;
1366
+ }
1367
+ }
1368
+
1369
+ exports.ConstantString = ConstantString;
1370
+ exports.SpecParser = SpecParser;
1371
+ exports.SpecParserError = SpecParserError;
1372
+ //# sourceMappingURL=index.node.cjs.js.map