@microsoft/m365-spec-parser 0.2.1 → 0.2.2-alpha.070ff93c3.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.
@@ -59,10 +59,12 @@ exports.ErrorType = void 0;
59
59
  ErrorType["RelativeServerUrlNotSupported"] = "relative-server-url-not-supported";
60
60
  ErrorType["NoSupportedApi"] = "no-supported-api";
61
61
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
62
+ ErrorType["AddedAPINotInOriginalSpec"] = "added-api-not-in-original-spec";
62
63
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
63
64
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
64
65
  ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
65
66
  ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
67
+ ErrorType["CircularReferenceNotSupported"] = "circular-reference-not-supported";
66
68
  ErrorType["ListFailed"] = "list-failed";
67
69
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
68
70
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -299,21 +301,28 @@ class Utils {
299
301
  static updateFirstLetter(str) {
300
302
  return str.charAt(0).toUpperCase() + str.slice(1);
301
303
  }
302
- static getResponseJson(operationObject) {
303
- var _a, _b;
304
+ static getResponseJson(operationObject, allowMultipleMediaType = false) {
305
+ var _a;
304
306
  let json = {};
305
307
  let multipleMediaType = false;
306
308
  for (const code of ConstantString.ResponseCodeFor20X) {
307
309
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
308
- if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
309
- multipleMediaType = false;
310
- json = responseObject.content["application/json"];
311
- if (Utils.containMultipleMediaTypes(responseObject)) {
312
- multipleMediaType = true;
313
- json = {};
314
- }
315
- else {
316
- break;
310
+ if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
311
+ for (const contentType of Object.keys(responseObject.content)) {
312
+ // json media type can also be "application/json; charset=utf-8"
313
+ if (contentType.indexOf("application/json") >= 0) {
314
+ multipleMediaType = false;
315
+ json = responseObject.content[contentType];
316
+ if (Utils.containMultipleMediaTypes(responseObject)) {
317
+ multipleMediaType = true;
318
+ if (!allowMultipleMediaType) {
319
+ json = {};
320
+ }
321
+ }
322
+ else {
323
+ return { json, multipleMediaType };
324
+ }
325
+ }
317
326
  }
318
327
  }
319
328
  }
@@ -574,10 +583,46 @@ class Utils {
574
583
  const serverUrl = operationServer || methodServer || rootServer;
575
584
  return serverUrl;
576
585
  }
586
+ static limitACBodyProperties(body, maxCount) {
587
+ const result = [];
588
+ let currentCount = 0;
589
+ for (const element of body) {
590
+ if (element.type === ConstantString.ContainerType) {
591
+ const items = this.limitACBodyProperties(element.items, maxCount - currentCount);
592
+ result.push({
593
+ type: ConstantString.ContainerType,
594
+ $data: element.$data,
595
+ items: items,
596
+ });
597
+ currentCount += items.length;
598
+ }
599
+ else {
600
+ result.push(element);
601
+ currentCount++;
602
+ }
603
+ if (currentCount >= maxCount) {
604
+ break;
605
+ }
606
+ }
607
+ return result;
608
+ }
577
609
  }
578
610
 
579
611
  // Copyright (c) Microsoft Corporation.
580
612
  class Validator {
613
+ constructor() {
614
+ this.hasCircularReference = false;
615
+ }
616
+ checkCircularReference() {
617
+ try {
618
+ JSON.stringify(this.spec);
619
+ }
620
+ catch (e) {
621
+ if (e.message.includes("Converting circular structure to JSON")) {
622
+ this.hasCircularReference = true;
623
+ }
624
+ }
625
+ }
581
626
  listAPIs() {
582
627
  var _a;
583
628
  if (this.apiMap) {
@@ -673,6 +718,22 @@ class Validator {
673
718
  }
674
719
  return result;
675
720
  }
721
+ validateCircularReference(method, path) {
722
+ const result = { isValid: true, reason: [] };
723
+ if (this.hasCircularReference) {
724
+ const operationObject = this.spec.paths[path][method];
725
+ try {
726
+ JSON.stringify(operationObject);
727
+ }
728
+ catch (e) {
729
+ if (e.message.includes("Converting circular structure to JSON")) {
730
+ result.isValid = false;
731
+ result.reason.push(exports.ErrorType.CircularReferenceNotSupported);
732
+ }
733
+ }
734
+ }
735
+ return result;
736
+ }
676
737
  validateResponse(method, path) {
677
738
  const result = { isValid: true, reason: [] };
678
739
  const operationObject = this.spec.paths[path][method];
@@ -861,6 +922,7 @@ class CopilotValidator extends Validator {
861
922
  this.projectType = exports.ProjectType.Copilot;
862
923
  this.options = options;
863
924
  this.spec = spec;
925
+ this.checkCircularReference();
864
926
  }
865
927
  validateSpec() {
866
928
  const result = { errors: [], warnings: [] };
@@ -886,6 +948,10 @@ class CopilotValidator extends Validator {
886
948
  if (!methodAndPathResult.isValid) {
887
949
  return methodAndPathResult;
888
950
  }
951
+ const circularReferenceResult = this.validateCircularReference(method, path);
952
+ if (!circularReferenceResult.isValid) {
953
+ return circularReferenceResult;
954
+ }
889
955
  const operationObject = this.spec.paths[path][method];
890
956
  // validate auth
891
957
  const authCheckResult = this.validateAuth(method, path);
@@ -929,6 +995,7 @@ class SMEValidator extends Validator {
929
995
  this.projectType = exports.ProjectType.SME;
930
996
  this.options = options;
931
997
  this.spec = spec;
998
+ this.checkCircularReference();
932
999
  }
933
1000
  validateSpec() {
934
1001
  const result = { errors: [], warnings: [] };
@@ -956,6 +1023,10 @@ class SMEValidator extends Validator {
956
1023
  if (!methodAndPathResult.isValid) {
957
1024
  return methodAndPathResult;
958
1025
  }
1026
+ const circularReferenceResult = this.validateCircularReference(method, path);
1027
+ if (!circularReferenceResult.isValid) {
1028
+ return circularReferenceResult;
1029
+ }
959
1030
  const operationObject = this.spec.paths[path][method];
960
1031
  // validate auth
961
1032
  const authCheckResult = this.validateAuth(method, path);
@@ -1026,6 +1097,7 @@ class TeamsAIValidator extends Validator {
1026
1097
  this.projectType = exports.ProjectType.TeamsAi;
1027
1098
  this.options = options;
1028
1099
  this.spec = spec;
1100
+ this.checkCircularReference();
1029
1101
  }
1030
1102
  validateSpec() {
1031
1103
  const result = { errors: [], warnings: [] };
@@ -1045,6 +1117,10 @@ class TeamsAIValidator extends Validator {
1045
1117
  if (!methodAndPathResult.isValid) {
1046
1118
  return methodAndPathResult;
1047
1119
  }
1120
+ const circularReferenceResult = this.validateCircularReference(method, path);
1121
+ if (!circularReferenceResult.isValid) {
1122
+ return circularReferenceResult;
1123
+ }
1048
1124
  const operationObject = this.spec.paths[path][method];
1049
1125
  // validate operationId
1050
1126
  if (!this.options.allowMissingId && !operationObject.operationId) {
@@ -1077,6 +1153,161 @@ class ValidatorFactory {
1077
1153
  }
1078
1154
  }
1079
1155
 
1156
+ // Copyright (c) Microsoft Corporation.
1157
+ class SpecOptimizer {
1158
+ static optimize(spec, options) {
1159
+ const mergedOptions = Object.assign(Object.assign({}, SpecOptimizer.defaultOptions), (options !== null && options !== void 0 ? options : {}));
1160
+ const newSpec = JSON.parse(JSON.stringify(spec));
1161
+ if (mergedOptions.removeUserDefinedRootProperty) {
1162
+ SpecOptimizer.removeUserDefinedRootProperty(newSpec);
1163
+ }
1164
+ if (mergedOptions.removeUnusedComponents) {
1165
+ SpecOptimizer.removeUnusedComponents(newSpec);
1166
+ }
1167
+ if (mergedOptions.removeUnusedTags) {
1168
+ SpecOptimizer.removeUnusedTags(newSpec);
1169
+ }
1170
+ if (mergedOptions.removeUnusedSecuritySchemas) {
1171
+ SpecOptimizer.removeUnusedSecuritySchemas(newSpec);
1172
+ }
1173
+ return newSpec;
1174
+ }
1175
+ static removeUnusedSecuritySchemas(spec) {
1176
+ if (!spec.components || !spec.components.securitySchemes) {
1177
+ return;
1178
+ }
1179
+ const usedSecuritySchemas = new Set();
1180
+ for (const pathKey in spec.paths) {
1181
+ for (const methodKey in spec.paths[pathKey]) {
1182
+ const operation = spec.paths[pathKey][methodKey];
1183
+ if (operation.security) {
1184
+ operation.security.forEach((securityReq) => {
1185
+ for (const schemaKey in securityReq) {
1186
+ usedSecuritySchemas.add(schemaKey);
1187
+ }
1188
+ });
1189
+ }
1190
+ }
1191
+ }
1192
+ if (spec.security) {
1193
+ spec.security.forEach((securityReq) => {
1194
+ for (const schemaKey in securityReq) {
1195
+ usedSecuritySchemas.add(schemaKey);
1196
+ }
1197
+ });
1198
+ }
1199
+ for (const schemaKey in spec.components.securitySchemes) {
1200
+ if (!usedSecuritySchemas.has(schemaKey)) {
1201
+ delete spec.components.securitySchemes[schemaKey];
1202
+ }
1203
+ }
1204
+ if (Object.keys(spec.components.securitySchemes).length === 0) {
1205
+ delete spec.components.securitySchemes;
1206
+ }
1207
+ if (Object.keys(spec.components).length === 0) {
1208
+ delete spec.components;
1209
+ }
1210
+ }
1211
+ static removeUnusedTags(spec) {
1212
+ if (!spec.tags) {
1213
+ return;
1214
+ }
1215
+ const usedTags = new Set();
1216
+ for (const pathKey in spec.paths) {
1217
+ for (const methodKey in spec.paths[pathKey]) {
1218
+ const operation = spec.paths[pathKey][methodKey];
1219
+ if (operation.tags) {
1220
+ operation.tags.forEach((tag) => usedTags.add(tag));
1221
+ }
1222
+ }
1223
+ }
1224
+ spec.tags = spec.tags.filter((tagObj) => usedTags.has(tagObj.name));
1225
+ }
1226
+ static removeUserDefinedRootProperty(spec) {
1227
+ for (const key in spec) {
1228
+ if (key.startsWith("x-")) {
1229
+ delete spec[key];
1230
+ }
1231
+ }
1232
+ }
1233
+ static removeUnusedComponents(spec) {
1234
+ const components = spec.components;
1235
+ if (!components) {
1236
+ return;
1237
+ }
1238
+ delete spec.components;
1239
+ const usedComponentsSet = new Set();
1240
+ const specString = JSON.stringify(spec);
1241
+ const componentReferences = SpecOptimizer.getComponentReferences(specString);
1242
+ for (const reference of componentReferences) {
1243
+ this.addComponent(reference, usedComponentsSet, components);
1244
+ }
1245
+ const newComponents = {};
1246
+ for (const componentName of usedComponentsSet) {
1247
+ const parts = componentName.split("/");
1248
+ const component = this.getComponent(componentName, components);
1249
+ if (component) {
1250
+ let current = newComponents;
1251
+ for (let i = 2; i < parts.length; i++) {
1252
+ if (i === parts.length - 1) {
1253
+ current[parts[i]] = component;
1254
+ }
1255
+ else if (!current[parts[i]]) {
1256
+ current[parts[i]] = {};
1257
+ }
1258
+ current = current[parts[i]];
1259
+ }
1260
+ }
1261
+ }
1262
+ // securitySchemes are referenced directly by name, to void issue, just keep them all and use removeUnusedSecuritySchemas to remove unused ones
1263
+ if (components.securitySchemes) {
1264
+ newComponents.securitySchemes = components.securitySchemes;
1265
+ }
1266
+ if (Object.keys(newComponents).length !== 0) {
1267
+ spec.components = newComponents;
1268
+ }
1269
+ }
1270
+ static getComponentReferences(specString) {
1271
+ const matches = Array.from(specString.matchAll(/['"](#\/components\/.+?)['"]/g));
1272
+ const matchResult = matches.map((match) => match[1]);
1273
+ return matchResult;
1274
+ }
1275
+ static getComponent(componentPath, components) {
1276
+ const parts = componentPath.split("/");
1277
+ let current = components;
1278
+ for (const part of parts) {
1279
+ if (part === "#" || part === "components") {
1280
+ continue;
1281
+ }
1282
+ current = current[part];
1283
+ if (!current) {
1284
+ return null;
1285
+ }
1286
+ }
1287
+ return current;
1288
+ }
1289
+ static addComponent(componentName, usedComponentsSet, components) {
1290
+ if (usedComponentsSet.has(componentName)) {
1291
+ return;
1292
+ }
1293
+ usedComponentsSet.add(componentName);
1294
+ const component = this.getComponent(componentName, components);
1295
+ if (component) {
1296
+ const componentString = JSON.stringify(component);
1297
+ const componentReferences = SpecOptimizer.getComponentReferences(componentString);
1298
+ for (const reference of componentReferences) {
1299
+ this.addComponent(reference, usedComponentsSet, components);
1300
+ }
1301
+ }
1302
+ }
1303
+ }
1304
+ SpecOptimizer.defaultOptions = {
1305
+ removeUnusedComponents: true,
1306
+ removeUnusedTags: true,
1307
+ removeUserDefinedRootProperty: true,
1308
+ removeUnusedSecuritySchemas: true,
1309
+ };
1310
+
1080
1311
  // Copyright (c) Microsoft Corporation.
1081
1312
  class SpecFilter {
1082
1313
  static specFilter(filter, unResolveSpec, resolvedSpec, options) {
@@ -1110,7 +1341,7 @@ class SpecFilter {
1110
1341
  }
1111
1342
  }
1112
1343
  newSpec.paths = newPaths;
1113
- return newSpec;
1344
+ return SpecOptimizer.optimize(newSpec);
1114
1345
  }
1115
1346
  catch (err) {
1116
1347
  throw new SpecParserError(err.toString(), exports.ErrorType.FilterSpecFailed);
@@ -1120,9 +1351,9 @@ class SpecFilter {
1120
1351
 
1121
1352
  // Copyright (c) Microsoft Corporation.
1122
1353
  class AdaptiveCardGenerator {
1123
- static generateAdaptiveCard(operationItem) {
1354
+ static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
1124
1355
  try {
1125
- const { json } = Utils.getResponseJson(operationItem);
1356
+ const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
1126
1357
  let cardBody = [];
1127
1358
  let schema = json.schema;
1128
1359
  let jsonPath = "$";
@@ -1233,7 +1464,7 @@ class AdaptiveCardGenerator {
1233
1464
  {
1234
1465
  type: "Image",
1235
1466
  url: `\${${name}}`,
1236
- $when: `\${${name} != null}`,
1467
+ $when: `\${${name} != null && ${name} != ''}`,
1237
1468
  },
1238
1469
  ];
1239
1470
  }
@@ -1242,7 +1473,7 @@ class AdaptiveCardGenerator {
1242
1473
  {
1243
1474
  type: "Image",
1244
1475
  url: "${$data}",
1245
- $when: "${$data != null}",
1476
+ $when: "${$data != null && $data != ''}",
1246
1477
  },
1247
1478
  ];
1248
1479
  }
@@ -1335,7 +1566,7 @@ function inferPreviewCardTemplate(card) {
1335
1566
  result.image = {
1336
1567
  url: `\${${inferredProperties.imageUrl}}`,
1337
1568
  alt: `\${if(${inferredProperties.imageUrl}, ${inferredProperties.imageUrl}, 'N/A')}`,
1338
- $when: `\${${inferredProperties.imageUrl} != null}`,
1569
+ $when: `\${${inferredProperties.imageUrl} != null && ${inferredProperties.imageUrl} != ''}`,
1339
1570
  };
1340
1571
  }
1341
1572
  return result;
@@ -1480,6 +1711,7 @@ class ManifestUpdater {
1480
1711
  const confirmationBodies = [];
1481
1712
  if (operationItem) {
1482
1713
  const operationId = operationItem.operationId;
1714
+ const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
1483
1715
  const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1484
1716
  const summary = operationItem.summary;
1485
1717
  const paramObject = operationItem.parameters;
@@ -1507,7 +1739,7 @@ class ManifestUpdater {
1507
1739
  }
1508
1740
  }
1509
1741
  const funcObj = {
1510
- name: operationId,
1742
+ name: safeFunctionName,
1511
1743
  description: description,
1512
1744
  };
1513
1745
  if (options.allowResponseSemantics) {
@@ -1515,7 +1747,7 @@ class ManifestUpdater {
1515
1747
  const { json } = Utils.getResponseJson(operationItem);
1516
1748
  if (json.schema) {
1517
1749
  const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem);
1518
- card.body = card.body.slice(0, 5);
1750
+ card.body = Utils.limitACBodyProperties(card.body, 5);
1519
1751
  const responseSemantic = wrapResponseSemantics(card, jsonPath);
1520
1752
  funcObj.capabilities = {
1521
1753
  response_semantics: responseSemantic,
@@ -1543,7 +1775,7 @@ class ManifestUpdater {
1543
1775
  }
1544
1776
  }
1545
1777
  functions.push(funcObj);
1546
- functionNames.push(operationId);
1778
+ functionNames.push(safeFunctionName);
1547
1779
  const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
1548
1780
  if (conversationStarterStr) {
1549
1781
  conversationStarters.push(conversationStarterStr);
@@ -1643,7 +1875,6 @@ class ManifestUpdater {
1643
1875
  const auth = authInfo.authScheme;
1644
1876
  const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1645
1877
  if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1646
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1647
1878
  composeExtension.authorization = {
1648
1879
  authType: "apiSecretServiceAuth",
1649
1880
  apiSecretServiceAuthConfiguration: {
@@ -1652,16 +1883,13 @@ class ManifestUpdater {
1652
1883
  };
1653
1884
  }
1654
1885
  else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
1886
+ // TODO: below schema is coming from design doc, may need to update when shcema is finalized
1655
1887
  composeExtension.authorization = {
1656
1888
  authType: "oAuth2.0",
1657
1889
  oAuthConfiguration: {
1658
1890
  oauthConfigurationId: `\${{${safeRegistrationIdName}}}`,
1659
1891
  },
1660
1892
  };
1661
- updatedPart.webApplicationInfo = {
1662
- id: "${{AAD_APP_CLIENT_ID}}",
1663
- resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
1664
- };
1665
1893
  }
1666
1894
  }
1667
1895
  updatedPart.composeExtensions = [composeExtension];
@@ -1699,12 +1927,17 @@ class ManifestUpdater {
1699
1927
  command.parameters = command.parameters.filter((param) => param.isRequired);
1700
1928
  }
1701
1929
  else if (command.parameters && command.parameters.length > 0) {
1702
- command.parameters = [command.parameters[0]];
1703
- warnings.push({
1704
- type: exports.WarningType.OperationOnlyContainsOptionalParam,
1705
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
1706
- data: command.id,
1707
- });
1930
+ if (command.parameters.length > 1) {
1931
+ command.parameters = [command.parameters[0]];
1932
+ warnings.push({
1933
+ type: exports.WarningType.OperationOnlyContainsOptionalParam,
1934
+ content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
1935
+ data: {
1936
+ commandId: command.id,
1937
+ parameterName: command.parameters[0].name,
1938
+ },
1939
+ });
1940
+ }
1708
1941
  }
1709
1942
  if (adaptiveCardFolder) {
1710
1943
  const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
@@ -1782,7 +2015,13 @@ class SpecParser {
1782
2015
  try {
1783
2016
  try {
1784
2017
  yield this.loadSpec();
1785
- yield this.parser.validate(this.spec);
2018
+ if (!this.parser.$refs.circular) {
2019
+ yield this.parser.validate(this.spec);
2020
+ }
2021
+ else {
2022
+ const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
2023
+ yield this.parser.validate(clonedUnResolveSpec);
2024
+ }
1786
2025
  }
1787
2026
  catch (e) {
1788
2027
  return {
@@ -1874,19 +2113,36 @@ class SpecParser {
1874
2113
  isValid: isValid,
1875
2114
  reason: reason,
1876
2115
  };
1877
- if (isValid) {
2116
+ // Try best to parse server url and auth type
2117
+ try {
1878
2118
  const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
1879
2119
  if (serverObj) {
1880
- apiResult.server = Utils.resolveEnv(serverObj.url);
2120
+ apiResult.server = serverObj.url;
1881
2121
  }
2122
+ }
2123
+ catch (err) {
2124
+ // ignore
2125
+ }
2126
+ try {
1882
2127
  const authArray = Utils.getAuthArray(operation.security, spec);
1883
- for (const auths of authArray) {
1884
- if (auths.length === 1) {
1885
- apiResult.auth = auths[0];
1886
- break;
2128
+ if (authArray.length !== 0) {
2129
+ for (const auths of authArray) {
2130
+ if (auths.length === 1) {
2131
+ apiResult.auth = auths[0];
2132
+ break;
2133
+ }
2134
+ else {
2135
+ apiResult.auth = {
2136
+ authScheme: { type: "multipleAuth" },
2137
+ name: auths.map((auth) => auth.name).join(", "),
2138
+ };
2139
+ }
1887
2140
  }
1888
2141
  }
1889
2142
  }
2143
+ catch (err) {
2144
+ // ignore
2145
+ }
1890
2146
  result.APIs.push(apiResult);
1891
2147
  }
1892
2148
  result.allAPICount = result.APIs.length;
@@ -1919,7 +2175,8 @@ class SpecParser {
1919
2175
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1920
2176
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1921
2177
  }
1922
- const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
2178
+ const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
2179
+ const newSpec = (yield this.parser.dereference(clonedUnResolveSpec));
1923
2180
  return [newUnResolvedSpec, newSpec];
1924
2181
  }
1925
2182
  catch (err) {
@@ -1996,10 +2253,11 @@ class SpecParser {
1996
2253
  const operation = newSpec.paths[url][method];
1997
2254
  try {
1998
2255
  const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1999
- const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
2256
+ const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
2257
+ const fileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
2000
2258
  const wrappedCard = wrapAdaptiveCard(card, jsonPath);
2001
2259
  yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
2002
- const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
2260
+ const dataFileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
2003
2261
  yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
2004
2262
  }
2005
2263
  catch (err) {
@@ -2033,7 +2291,8 @@ class SpecParser {
2033
2291
  loadSpec() {
2034
2292
  return __awaiter(this, void 0, void 0, function* () {
2035
2293
  if (!this.spec) {
2036
- this.unResolveSpec = (yield this.parser.parse(this.pathOrSpec));
2294
+ const spec = (yield this.parser.parse(this.pathOrSpec));
2295
+ this.unResolveSpec = this.resolveEnvForSpec(spec);
2037
2296
  // Convert swagger 2.0 to openapi 3.0
2038
2297
  if (!this.unResolveSpec.openapi && this.unResolveSpec.swagger === "2.0") {
2039
2298
  const specObj = yield converter__default['default'].convert(this.unResolveSpec, {});
@@ -2070,6 +2329,11 @@ class SpecParser {
2070
2329
  yield fs__default['default'].outputFile(outputSpecPath, resultStr);
2071
2330
  });
2072
2331
  }
2332
+ resolveEnvForSpec(spec) {
2333
+ const specString = JSON.stringify(spec);
2334
+ const specResolved = Utils.resolveEnv(specString);
2335
+ return JSON.parse(specResolved);
2336
+ }
2073
2337
  }
2074
2338
 
2075
2339
  exports.AdaptiveCardGenerator = AdaptiveCardGenerator;