@microsoft/m365-spec-parser 0.2.1-rc-hotfix.0 → 0.2.2-alpha.02a122217.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.
@@ -17,10 +17,12 @@ var ErrorType;
17
17
  ErrorType["RelativeServerUrlNotSupported"] = "relative-server-url-not-supported";
18
18
  ErrorType["NoSupportedApi"] = "no-supported-api";
19
19
  ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
20
+ ErrorType["AddedAPINotInOriginalSpec"] = "added-api-not-in-original-spec";
20
21
  ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
21
22
  ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
22
23
  ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
23
24
  ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
25
+ ErrorType["CircularReferenceNotSupported"] = "circular-reference-not-supported";
24
26
  ErrorType["ListFailed"] = "list-failed";
25
27
  ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
26
28
  ErrorType["FilterSpecFailed"] = "filter-spec-failed";
@@ -257,21 +259,28 @@ class Utils {
257
259
  static updateFirstLetter(str) {
258
260
  return str.charAt(0).toUpperCase() + str.slice(1);
259
261
  }
260
- static getResponseJson(operationObject) {
261
- var _a, _b;
262
+ static getResponseJson(operationObject, allowMultipleMediaType = false) {
263
+ var _a;
262
264
  let json = {};
263
265
  let multipleMediaType = false;
264
266
  for (const code of ConstantString.ResponseCodeFor20X) {
265
267
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
266
- if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
267
- multipleMediaType = false;
268
- json = responseObject.content["application/json"];
269
- if (Utils.containMultipleMediaTypes(responseObject)) {
270
- multipleMediaType = true;
271
- json = {};
272
- }
273
- else {
274
- break;
268
+ if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
269
+ for (const contentType of Object.keys(responseObject.content)) {
270
+ // json media type can also be "application/json; charset=utf-8"
271
+ if (contentType.indexOf("application/json") >= 0) {
272
+ multipleMediaType = false;
273
+ json = responseObject.content[contentType];
274
+ if (Utils.containMultipleMediaTypes(responseObject)) {
275
+ multipleMediaType = true;
276
+ if (!allowMultipleMediaType) {
277
+ json = {};
278
+ }
279
+ }
280
+ else {
281
+ return { json, multipleMediaType };
282
+ }
283
+ }
275
284
  }
276
285
  }
277
286
  }
@@ -532,10 +541,46 @@ class Utils {
532
541
  const serverUrl = operationServer || methodServer || rootServer;
533
542
  return serverUrl;
534
543
  }
544
+ static limitACBodyProperties(body, maxCount) {
545
+ const result = [];
546
+ let currentCount = 0;
547
+ for (const element of body) {
548
+ if (element.type === ConstantString.ContainerType) {
549
+ const items = this.limitACBodyProperties(element.items, maxCount - currentCount);
550
+ result.push({
551
+ type: ConstantString.ContainerType,
552
+ $data: element.$data,
553
+ items: items,
554
+ });
555
+ currentCount += items.length;
556
+ }
557
+ else {
558
+ result.push(element);
559
+ currentCount++;
560
+ }
561
+ if (currentCount >= maxCount) {
562
+ break;
563
+ }
564
+ }
565
+ return result;
566
+ }
535
567
  }
536
568
 
537
569
  // Copyright (c) Microsoft Corporation.
538
570
  class Validator {
571
+ constructor() {
572
+ this.hasCircularReference = false;
573
+ }
574
+ checkCircularReference() {
575
+ try {
576
+ JSON.stringify(this.spec);
577
+ }
578
+ catch (e) {
579
+ if (e.message.includes("Converting circular structure to JSON")) {
580
+ this.hasCircularReference = true;
581
+ }
582
+ }
583
+ }
539
584
  listAPIs() {
540
585
  var _a;
541
586
  if (this.apiMap) {
@@ -631,6 +676,22 @@ class Validator {
631
676
  }
632
677
  return result;
633
678
  }
679
+ validateCircularReference(method, path) {
680
+ const result = { isValid: true, reason: [] };
681
+ if (this.hasCircularReference) {
682
+ const operationObject = this.spec.paths[path][method];
683
+ try {
684
+ JSON.stringify(operationObject);
685
+ }
686
+ catch (e) {
687
+ if (e.message.includes("Converting circular structure to JSON")) {
688
+ result.isValid = false;
689
+ result.reason.push(ErrorType.CircularReferenceNotSupported);
690
+ }
691
+ }
692
+ }
693
+ return result;
694
+ }
634
695
  validateResponse(method, path) {
635
696
  const result = { isValid: true, reason: [] };
636
697
  const operationObject = this.spec.paths[path][method];
@@ -819,6 +880,7 @@ class CopilotValidator extends Validator {
819
880
  this.projectType = ProjectType.Copilot;
820
881
  this.options = options;
821
882
  this.spec = spec;
883
+ this.checkCircularReference();
822
884
  }
823
885
  validateSpec() {
824
886
  const result = { errors: [], warnings: [] };
@@ -844,6 +906,10 @@ class CopilotValidator extends Validator {
844
906
  if (!methodAndPathResult.isValid) {
845
907
  return methodAndPathResult;
846
908
  }
909
+ const circularReferenceResult = this.validateCircularReference(method, path);
910
+ if (!circularReferenceResult.isValid) {
911
+ return circularReferenceResult;
912
+ }
847
913
  const operationObject = this.spec.paths[path][method];
848
914
  // validate auth
849
915
  const authCheckResult = this.validateAuth(method, path);
@@ -887,6 +953,7 @@ class SMEValidator extends Validator {
887
953
  this.projectType = ProjectType.SME;
888
954
  this.options = options;
889
955
  this.spec = spec;
956
+ this.checkCircularReference();
890
957
  }
891
958
  validateSpec() {
892
959
  const result = { errors: [], warnings: [] };
@@ -914,6 +981,10 @@ class SMEValidator extends Validator {
914
981
  if (!methodAndPathResult.isValid) {
915
982
  return methodAndPathResult;
916
983
  }
984
+ const circularReferenceResult = this.validateCircularReference(method, path);
985
+ if (!circularReferenceResult.isValid) {
986
+ return circularReferenceResult;
987
+ }
917
988
  const operationObject = this.spec.paths[path][method];
918
989
  // validate auth
919
990
  const authCheckResult = this.validateAuth(method, path);
@@ -984,6 +1055,7 @@ class TeamsAIValidator extends Validator {
984
1055
  this.projectType = ProjectType.TeamsAi;
985
1056
  this.options = options;
986
1057
  this.spec = spec;
1058
+ this.checkCircularReference();
987
1059
  }
988
1060
  validateSpec() {
989
1061
  const result = { errors: [], warnings: [] };
@@ -1003,6 +1075,10 @@ class TeamsAIValidator extends Validator {
1003
1075
  if (!methodAndPathResult.isValid) {
1004
1076
  return methodAndPathResult;
1005
1077
  }
1078
+ const circularReferenceResult = this.validateCircularReference(method, path);
1079
+ if (!circularReferenceResult.isValid) {
1080
+ return circularReferenceResult;
1081
+ }
1006
1082
  const operationObject = this.spec.paths[path][method];
1007
1083
  // validate operationId
1008
1084
  if (!this.options.allowMissingId && !operationObject.operationId) {
@@ -1035,6 +1111,161 @@ class ValidatorFactory {
1035
1111
  }
1036
1112
  }
1037
1113
 
1114
+ // Copyright (c) Microsoft Corporation.
1115
+ class SpecOptimizer {
1116
+ static optimize(spec, options) {
1117
+ const mergedOptions = Object.assign(Object.assign({}, SpecOptimizer.defaultOptions), (options !== null && options !== void 0 ? options : {}));
1118
+ const newSpec = JSON.parse(JSON.stringify(spec));
1119
+ if (mergedOptions.removeUserDefinedRootProperty) {
1120
+ SpecOptimizer.removeUserDefinedRootProperty(newSpec);
1121
+ }
1122
+ if (mergedOptions.removeUnusedComponents) {
1123
+ SpecOptimizer.removeUnusedComponents(newSpec);
1124
+ }
1125
+ if (mergedOptions.removeUnusedTags) {
1126
+ SpecOptimizer.removeUnusedTags(newSpec);
1127
+ }
1128
+ if (mergedOptions.removeUnusedSecuritySchemas) {
1129
+ SpecOptimizer.removeUnusedSecuritySchemas(newSpec);
1130
+ }
1131
+ return newSpec;
1132
+ }
1133
+ static removeUnusedSecuritySchemas(spec) {
1134
+ if (!spec.components || !spec.components.securitySchemes) {
1135
+ return;
1136
+ }
1137
+ const usedSecuritySchemas = new Set();
1138
+ for (const pathKey in spec.paths) {
1139
+ for (const methodKey in spec.paths[pathKey]) {
1140
+ const operation = spec.paths[pathKey][methodKey];
1141
+ if (operation.security) {
1142
+ operation.security.forEach((securityReq) => {
1143
+ for (const schemaKey in securityReq) {
1144
+ usedSecuritySchemas.add(schemaKey);
1145
+ }
1146
+ });
1147
+ }
1148
+ }
1149
+ }
1150
+ if (spec.security) {
1151
+ spec.security.forEach((securityReq) => {
1152
+ for (const schemaKey in securityReq) {
1153
+ usedSecuritySchemas.add(schemaKey);
1154
+ }
1155
+ });
1156
+ }
1157
+ for (const schemaKey in spec.components.securitySchemes) {
1158
+ if (!usedSecuritySchemas.has(schemaKey)) {
1159
+ delete spec.components.securitySchemes[schemaKey];
1160
+ }
1161
+ }
1162
+ if (Object.keys(spec.components.securitySchemes).length === 0) {
1163
+ delete spec.components.securitySchemes;
1164
+ }
1165
+ if (Object.keys(spec.components).length === 0) {
1166
+ delete spec.components;
1167
+ }
1168
+ }
1169
+ static removeUnusedTags(spec) {
1170
+ if (!spec.tags) {
1171
+ return;
1172
+ }
1173
+ const usedTags = new Set();
1174
+ for (const pathKey in spec.paths) {
1175
+ for (const methodKey in spec.paths[pathKey]) {
1176
+ const operation = spec.paths[pathKey][methodKey];
1177
+ if (operation.tags) {
1178
+ operation.tags.forEach((tag) => usedTags.add(tag));
1179
+ }
1180
+ }
1181
+ }
1182
+ spec.tags = spec.tags.filter((tagObj) => usedTags.has(tagObj.name));
1183
+ }
1184
+ static removeUserDefinedRootProperty(spec) {
1185
+ for (const key in spec) {
1186
+ if (key.startsWith("x-")) {
1187
+ delete spec[key];
1188
+ }
1189
+ }
1190
+ }
1191
+ static removeUnusedComponents(spec) {
1192
+ const components = spec.components;
1193
+ if (!components) {
1194
+ return;
1195
+ }
1196
+ delete spec.components;
1197
+ const usedComponentsSet = new Set();
1198
+ const specString = JSON.stringify(spec);
1199
+ const componentReferences = SpecOptimizer.getComponentReferences(specString);
1200
+ for (const reference of componentReferences) {
1201
+ this.addComponent(reference, usedComponentsSet, components);
1202
+ }
1203
+ const newComponents = {};
1204
+ for (const componentName of usedComponentsSet) {
1205
+ const parts = componentName.split("/");
1206
+ const component = this.getComponent(componentName, components);
1207
+ if (component) {
1208
+ let current = newComponents;
1209
+ for (let i = 2; i < parts.length; i++) {
1210
+ if (i === parts.length - 1) {
1211
+ current[parts[i]] = component;
1212
+ }
1213
+ else if (!current[parts[i]]) {
1214
+ current[parts[i]] = {};
1215
+ }
1216
+ current = current[parts[i]];
1217
+ }
1218
+ }
1219
+ }
1220
+ // securitySchemes are referenced directly by name, to void issue, just keep them all and use removeUnusedSecuritySchemas to remove unused ones
1221
+ if (components.securitySchemes) {
1222
+ newComponents.securitySchemes = components.securitySchemes;
1223
+ }
1224
+ if (Object.keys(newComponents).length !== 0) {
1225
+ spec.components = newComponents;
1226
+ }
1227
+ }
1228
+ static getComponentReferences(specString) {
1229
+ const matches = Array.from(specString.matchAll(/['"](#\/components\/.+?)['"]/g));
1230
+ const matchResult = matches.map((match) => match[1]);
1231
+ return matchResult;
1232
+ }
1233
+ static getComponent(componentPath, components) {
1234
+ const parts = componentPath.split("/");
1235
+ let current = components;
1236
+ for (const part of parts) {
1237
+ if (part === "#" || part === "components") {
1238
+ continue;
1239
+ }
1240
+ current = current[part];
1241
+ if (!current) {
1242
+ return null;
1243
+ }
1244
+ }
1245
+ return current;
1246
+ }
1247
+ static addComponent(componentName, usedComponentsSet, components) {
1248
+ if (usedComponentsSet.has(componentName)) {
1249
+ return;
1250
+ }
1251
+ usedComponentsSet.add(componentName);
1252
+ const component = this.getComponent(componentName, components);
1253
+ if (component) {
1254
+ const componentString = JSON.stringify(component);
1255
+ const componentReferences = SpecOptimizer.getComponentReferences(componentString);
1256
+ for (const reference of componentReferences) {
1257
+ this.addComponent(reference, usedComponentsSet, components);
1258
+ }
1259
+ }
1260
+ }
1261
+ }
1262
+ SpecOptimizer.defaultOptions = {
1263
+ removeUnusedComponents: true,
1264
+ removeUnusedTags: true,
1265
+ removeUserDefinedRootProperty: true,
1266
+ removeUnusedSecuritySchemas: true,
1267
+ };
1268
+
1038
1269
  // Copyright (c) Microsoft Corporation.
1039
1270
  class SpecFilter {
1040
1271
  static specFilter(filter, unResolveSpec, resolvedSpec, options) {
@@ -1068,7 +1299,7 @@ class SpecFilter {
1068
1299
  }
1069
1300
  }
1070
1301
  newSpec.paths = newPaths;
1071
- return newSpec;
1302
+ return SpecOptimizer.optimize(newSpec);
1072
1303
  }
1073
1304
  catch (err) {
1074
1305
  throw new SpecParserError(err.toString(), ErrorType.FilterSpecFailed);
@@ -1078,9 +1309,9 @@ class SpecFilter {
1078
1309
 
1079
1310
  // Copyright (c) Microsoft Corporation.
1080
1311
  class AdaptiveCardGenerator {
1081
- static generateAdaptiveCard(operationItem) {
1312
+ static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
1082
1313
  try {
1083
- const { json } = Utils.getResponseJson(operationItem);
1314
+ const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
1084
1315
  let cardBody = [];
1085
1316
  let schema = json.schema;
1086
1317
  let jsonPath = "$";
@@ -1191,7 +1422,7 @@ class AdaptiveCardGenerator {
1191
1422
  {
1192
1423
  type: "Image",
1193
1424
  url: `\${${name}}`,
1194
- $when: `\${${name} != null}`,
1425
+ $when: `\${${name} != null && ${name} != ''}`,
1195
1426
  },
1196
1427
  ];
1197
1428
  }
@@ -1200,7 +1431,7 @@ class AdaptiveCardGenerator {
1200
1431
  {
1201
1432
  type: "Image",
1202
1433
  url: "${$data}",
1203
- $when: "${$data != null}",
1434
+ $when: "${$data != null && $data != ''}",
1204
1435
  },
1205
1436
  ];
1206
1437
  }
@@ -1293,7 +1524,7 @@ function inferPreviewCardTemplate(card) {
1293
1524
  result.image = {
1294
1525
  url: `\${${inferredProperties.imageUrl}}`,
1295
1526
  alt: `\${if(${inferredProperties.imageUrl}, ${inferredProperties.imageUrl}, 'N/A')}`,
1296
- $when: `\${${inferredProperties.imageUrl} != null}`,
1527
+ $when: `\${${inferredProperties.imageUrl} != null && ${inferredProperties.imageUrl} != ''}`,
1297
1528
  };
1298
1529
  }
1299
1530
  return result;
@@ -1435,6 +1666,7 @@ class ManifestUpdater {
1435
1666
  const confirmationBodies = [];
1436
1667
  if (operationItem) {
1437
1668
  const operationId = operationItem.operationId;
1669
+ const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
1438
1670
  const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1439
1671
  const summary = operationItem.summary;
1440
1672
  const paramObject = operationItem.parameters;
@@ -1462,7 +1694,7 @@ class ManifestUpdater {
1462
1694
  }
1463
1695
  }
1464
1696
  const funcObj = {
1465
- name: operationId,
1697
+ name: safeFunctionName,
1466
1698
  description: description,
1467
1699
  };
1468
1700
  if (options.allowResponseSemantics) {
@@ -1470,7 +1702,7 @@ class ManifestUpdater {
1470
1702
  const { json } = Utils.getResponseJson(operationItem);
1471
1703
  if (json.schema) {
1472
1704
  const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem);
1473
- card.body = card.body.slice(0, 5);
1705
+ card.body = Utils.limitACBodyProperties(card.body, 5);
1474
1706
  const responseSemantic = wrapResponseSemantics(card, jsonPath);
1475
1707
  funcObj.capabilities = {
1476
1708
  response_semantics: responseSemantic,
@@ -1498,7 +1730,7 @@ class ManifestUpdater {
1498
1730
  }
1499
1731
  }
1500
1732
  functions.push(funcObj);
1501
- functionNames.push(operationId);
1733
+ functionNames.push(safeFunctionName);
1502
1734
  const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
1503
1735
  if (conversationStarterStr) {
1504
1736
  conversationStarters.push(conversationStarterStr);
@@ -1596,7 +1828,6 @@ class ManifestUpdater {
1596
1828
  const auth = authInfo.authScheme;
1597
1829
  const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1598
1830
  if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1599
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1600
1831
  composeExtension.authorization = {
1601
1832
  authType: "apiSecretServiceAuth",
1602
1833
  apiSecretServiceAuthConfiguration: {
@@ -1605,16 +1836,13 @@ class ManifestUpdater {
1605
1836
  };
1606
1837
  }
1607
1838
  else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
1839
+ // TODO: below schema is coming from design doc, may need to update when shcema is finalized
1608
1840
  composeExtension.authorization = {
1609
1841
  authType: "oAuth2.0",
1610
1842
  oAuthConfiguration: {
1611
1843
  oauthConfigurationId: `\${{${safeRegistrationIdName}}}`,
1612
1844
  },
1613
1845
  };
1614
- updatedPart.webApplicationInfo = {
1615
- id: "${{AAD_APP_CLIENT_ID}}",
1616
- resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
1617
- };
1618
1846
  }
1619
1847
  }
1620
1848
  updatedPart.composeExtensions = [composeExtension];
@@ -1650,12 +1878,17 @@ class ManifestUpdater {
1650
1878
  command.parameters = command.parameters.filter((param) => param.isRequired);
1651
1879
  }
1652
1880
  else if (command.parameters && command.parameters.length > 0) {
1653
- command.parameters = [command.parameters[0]];
1654
- warnings.push({
1655
- type: WarningType.OperationOnlyContainsOptionalParam,
1656
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
1657
- data: command.id,
1658
- });
1881
+ if (command.parameters.length > 1) {
1882
+ command.parameters = [command.parameters[0]];
1883
+ warnings.push({
1884
+ type: WarningType.OperationOnlyContainsOptionalParam,
1885
+ content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
1886
+ data: {
1887
+ commandId: command.id,
1888
+ parameterName: command.parameters[0].name,
1889
+ },
1890
+ });
1891
+ }
1659
1892
  }
1660
1893
  if (adaptiveCardFolder) {
1661
1894
  const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
@@ -1731,7 +1964,13 @@ class SpecParser {
1731
1964
  try {
1732
1965
  try {
1733
1966
  await this.loadSpec();
1734
- await this.parser.validate(this.spec);
1967
+ if (!this.parser.$refs.circular) {
1968
+ await this.parser.validate(this.spec);
1969
+ }
1970
+ else {
1971
+ const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
1972
+ await this.parser.validate(clonedUnResolveSpec);
1973
+ }
1735
1974
  }
1736
1975
  catch (e) {
1737
1976
  return {
@@ -1819,19 +2058,36 @@ class SpecParser {
1819
2058
  isValid: isValid,
1820
2059
  reason: reason,
1821
2060
  };
1822
- if (isValid) {
2061
+ // Try best to parse server url and auth type
2062
+ try {
1823
2063
  const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
1824
2064
  if (serverObj) {
1825
- apiResult.server = Utils.resolveEnv(serverObj.url);
2065
+ apiResult.server = serverObj.url;
1826
2066
  }
2067
+ }
2068
+ catch (err) {
2069
+ // ignore
2070
+ }
2071
+ try {
1827
2072
  const authArray = Utils.getAuthArray(operation.security, spec);
1828
- for (const auths of authArray) {
1829
- if (auths.length === 1) {
1830
- apiResult.auth = auths[0];
1831
- break;
2073
+ if (authArray.length !== 0) {
2074
+ for (const auths of authArray) {
2075
+ if (auths.length === 1) {
2076
+ apiResult.auth = auths[0];
2077
+ break;
2078
+ }
2079
+ else {
2080
+ apiResult.auth = {
2081
+ authScheme: { type: "multipleAuth" },
2082
+ name: auths.map((auth) => auth.name).join(", "),
2083
+ };
2084
+ }
1832
2085
  }
1833
2086
  }
1834
2087
  }
2088
+ catch (err) {
2089
+ // ignore
2090
+ }
1835
2091
  result.APIs.push(apiResult);
1836
2092
  }
1837
2093
  result.allAPICount = result.APIs.length;
@@ -1862,7 +2118,8 @@ class SpecParser {
1862
2118
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1863
2119
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1864
2120
  }
1865
- const newSpec = (await this.parser.dereference(newUnResolvedSpec));
2121
+ const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
2122
+ const newSpec = (await this.parser.dereference(clonedUnResolveSpec));
1866
2123
  return [newUnResolvedSpec, newSpec];
1867
2124
  }
1868
2125
  catch (err) {
@@ -1935,10 +2192,11 @@ class SpecParser {
1935
2192
  const operation = newSpec.paths[url][method];
1936
2193
  try {
1937
2194
  const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1938
- const fileName = path.join(adaptiveCardFolder, `${operation.operationId}.json`);
2195
+ const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
2196
+ const fileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
1939
2197
  const wrappedCard = wrapAdaptiveCard(card, jsonPath);
1940
2198
  await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
1941
- const dataFileName = path.join(adaptiveCardFolder, `${operation.operationId}.data.json`);
2199
+ const dataFileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
1942
2200
  await fs.outputJSON(dataFileName, {}, { spaces: 2 });
1943
2201
  }
1944
2202
  catch (err) {
@@ -1970,7 +2228,8 @@ class SpecParser {
1970
2228
  }
1971
2229
  async loadSpec() {
1972
2230
  if (!this.spec) {
1973
- this.unResolveSpec = (await this.parser.parse(this.pathOrSpec));
2231
+ const spec = (await this.parser.parse(this.pathOrSpec));
2232
+ this.unResolveSpec = this.resolveEnvForSpec(spec);
1974
2233
  // Convert swagger 2.0 to openapi 3.0
1975
2234
  if (!this.unResolveSpec.openapi && this.unResolveSpec.swagger === "2.0") {
1976
2235
  const specObj = await converter.convert(this.unResolveSpec, {});
@@ -2004,6 +2263,11 @@ class SpecParser {
2004
2263
  }
2005
2264
  await fs.outputFile(outputSpecPath, resultStr);
2006
2265
  }
2266
+ resolveEnvForSpec(spec) {
2267
+ const specString = JSON.stringify(spec);
2268
+ const specResolved = Utils.resolveEnv(specString);
2269
+ return JSON.parse(specResolved);
2270
+ }
2007
2271
  }
2008
2272
 
2009
2273
  export { AdaptiveCardGenerator, ConstantString, ErrorType, ProjectType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };