@microsoft/m365-spec-parser 0.2.2-alpha.4a7c0c761.0 → 0.2.2-alpha.557dab381.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.
@@ -578,6 +578,28 @@ class Utils {
578
578
  const serverUrl = operationServer || methodServer || rootServer;
579
579
  return serverUrl;
580
580
  }
581
+ static limitACBodyProperties(body, maxCount) {
582
+ const result = [];
583
+ let currentCount = 0;
584
+ for (const element of body) {
585
+ if (element.type === ConstantString.ContainerType) {
586
+ const items = this.limitACBodyProperties(element.items, maxCount - currentCount);
587
+ result.push({
588
+ type: ConstantString.ContainerType,
589
+ $data: element.$data,
590
+ items: items,
591
+ });
592
+ currentCount += items.length;
593
+ }
594
+ else {
595
+ if (currentCount < maxCount) {
596
+ result.push(element);
597
+ currentCount++;
598
+ }
599
+ }
600
+ }
601
+ return result;
602
+ }
581
603
  }
582
604
 
583
605
  // Copyright (c) Microsoft Corporation.
@@ -1125,6 +1147,161 @@ class ValidatorFactory {
1125
1147
  }
1126
1148
  }
1127
1149
 
1150
+ // Copyright (c) Microsoft Corporation.
1151
+ class SpecOptimizer {
1152
+ static optimize(spec, options) {
1153
+ const mergedOptions = Object.assign(Object.assign({}, SpecOptimizer.defaultOptions), (options !== null && options !== void 0 ? options : {}));
1154
+ const newSpec = JSON.parse(JSON.stringify(spec));
1155
+ if (mergedOptions.removeUserDefinedRootProperty) {
1156
+ SpecOptimizer.removeUserDefinedRootProperty(newSpec);
1157
+ }
1158
+ if (mergedOptions.removeUnusedComponents) {
1159
+ SpecOptimizer.removeUnusedComponents(newSpec);
1160
+ }
1161
+ if (mergedOptions.removeUnusedTags) {
1162
+ SpecOptimizer.removeUnusedTags(newSpec);
1163
+ }
1164
+ if (mergedOptions.removeUnusedSecuritySchemas) {
1165
+ SpecOptimizer.removeUnusedSecuritySchemas(newSpec);
1166
+ }
1167
+ return newSpec;
1168
+ }
1169
+ static removeUnusedSecuritySchemas(spec) {
1170
+ if (!spec.components || !spec.components.securitySchemes) {
1171
+ return;
1172
+ }
1173
+ const usedSecuritySchemas = 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.security) {
1178
+ operation.security.forEach((securityReq) => {
1179
+ for (const schemaKey in securityReq) {
1180
+ usedSecuritySchemas.add(schemaKey);
1181
+ }
1182
+ });
1183
+ }
1184
+ }
1185
+ }
1186
+ if (spec.security) {
1187
+ spec.security.forEach((securityReq) => {
1188
+ for (const schemaKey in securityReq) {
1189
+ usedSecuritySchemas.add(schemaKey);
1190
+ }
1191
+ });
1192
+ }
1193
+ for (const schemaKey in spec.components.securitySchemes) {
1194
+ if (!usedSecuritySchemas.has(schemaKey)) {
1195
+ delete spec.components.securitySchemes[schemaKey];
1196
+ }
1197
+ }
1198
+ if (Object.keys(spec.components.securitySchemes).length === 0) {
1199
+ delete spec.components.securitySchemes;
1200
+ }
1201
+ if (Object.keys(spec.components).length === 0) {
1202
+ delete spec.components;
1203
+ }
1204
+ }
1205
+ static removeUnusedTags(spec) {
1206
+ if (!spec.tags) {
1207
+ return;
1208
+ }
1209
+ const usedTags = new Set();
1210
+ for (const pathKey in spec.paths) {
1211
+ for (const methodKey in spec.paths[pathKey]) {
1212
+ const operation = spec.paths[pathKey][methodKey];
1213
+ if (operation.tags) {
1214
+ operation.tags.forEach((tag) => usedTags.add(tag));
1215
+ }
1216
+ }
1217
+ }
1218
+ spec.tags = spec.tags.filter((tagObj) => usedTags.has(tagObj.name));
1219
+ }
1220
+ static removeUserDefinedRootProperty(spec) {
1221
+ for (const key in spec) {
1222
+ if (key.startsWith("x-")) {
1223
+ delete spec[key];
1224
+ }
1225
+ }
1226
+ }
1227
+ static removeUnusedComponents(spec) {
1228
+ const components = spec.components;
1229
+ if (!components) {
1230
+ return;
1231
+ }
1232
+ delete spec.components;
1233
+ const usedComponentsSet = new Set();
1234
+ const specString = JSON.stringify(spec);
1235
+ const componentReferences = SpecOptimizer.getComponentReferences(specString);
1236
+ for (const reference of componentReferences) {
1237
+ this.addComponent(reference, usedComponentsSet, components);
1238
+ }
1239
+ const newComponents = {};
1240
+ for (const componentName of usedComponentsSet) {
1241
+ const parts = componentName.split("/");
1242
+ const component = this.getComponent(componentName, components);
1243
+ if (component) {
1244
+ let current = newComponents;
1245
+ for (let i = 2; i < parts.length; i++) {
1246
+ if (i === parts.length - 1) {
1247
+ current[parts[i]] = component;
1248
+ }
1249
+ else if (!current[parts[i]]) {
1250
+ current[parts[i]] = {};
1251
+ }
1252
+ current = current[parts[i]];
1253
+ }
1254
+ }
1255
+ }
1256
+ // securitySchemes are referenced directly by name, to void issue, just keep them all and use removeUnusedSecuritySchemas to remove unused ones
1257
+ if (components.securitySchemes) {
1258
+ newComponents.securitySchemes = components.securitySchemes;
1259
+ }
1260
+ if (Object.keys(newComponents).length !== 0) {
1261
+ spec.components = newComponents;
1262
+ }
1263
+ }
1264
+ static getComponentReferences(specString) {
1265
+ const matches = Array.from(specString.matchAll(/['"](#\/components\/.+?)['"]/g));
1266
+ const matchResult = matches.map((match) => match[1]);
1267
+ return matchResult;
1268
+ }
1269
+ static getComponent(componentPath, components) {
1270
+ const parts = componentPath.split("/");
1271
+ let current = components;
1272
+ for (const part of parts) {
1273
+ if (part === "#" || part === "components") {
1274
+ continue;
1275
+ }
1276
+ current = current[part];
1277
+ if (!current) {
1278
+ return null;
1279
+ }
1280
+ }
1281
+ return current;
1282
+ }
1283
+ static addComponent(componentName, usedComponentsSet, components) {
1284
+ if (usedComponentsSet.has(componentName)) {
1285
+ return;
1286
+ }
1287
+ usedComponentsSet.add(componentName);
1288
+ const component = this.getComponent(componentName, components);
1289
+ if (component) {
1290
+ const componentString = JSON.stringify(component);
1291
+ const componentReferences = SpecOptimizer.getComponentReferences(componentString);
1292
+ for (const reference of componentReferences) {
1293
+ this.addComponent(reference, usedComponentsSet, components);
1294
+ }
1295
+ }
1296
+ }
1297
+ }
1298
+ SpecOptimizer.defaultOptions = {
1299
+ removeUnusedComponents: true,
1300
+ removeUnusedTags: true,
1301
+ removeUserDefinedRootProperty: true,
1302
+ removeUnusedSecuritySchemas: true,
1303
+ };
1304
+
1128
1305
  // Copyright (c) Microsoft Corporation.
1129
1306
  class SpecFilter {
1130
1307
  static specFilter(filter, unResolveSpec, resolvedSpec, options) {
@@ -1158,7 +1335,7 @@ class SpecFilter {
1158
1335
  }
1159
1336
  }
1160
1337
  newSpec.paths = newPaths;
1161
- return newSpec;
1338
+ return SpecOptimizer.optimize(newSpec);
1162
1339
  }
1163
1340
  catch (err) {
1164
1341
  throw new SpecParserError(err.toString(), exports.ErrorType.FilterSpecFailed);
@@ -1281,7 +1458,7 @@ class AdaptiveCardGenerator {
1281
1458
  {
1282
1459
  type: "Image",
1283
1460
  url: `\${${name}}`,
1284
- $when: `\${${name} != null}`,
1461
+ $when: `\${${name} != null && ${name} != ''}`,
1285
1462
  },
1286
1463
  ];
1287
1464
  }
@@ -1290,7 +1467,7 @@ class AdaptiveCardGenerator {
1290
1467
  {
1291
1468
  type: "Image",
1292
1469
  url: "${$data}",
1293
- $when: "${$data != null}",
1470
+ $when: "${$data != null && $data != ''}",
1294
1471
  },
1295
1472
  ];
1296
1473
  }
@@ -1383,7 +1560,7 @@ function inferPreviewCardTemplate(card) {
1383
1560
  result.image = {
1384
1561
  url: `\${${inferredProperties.imageUrl}}`,
1385
1562
  alt: `\${if(${inferredProperties.imageUrl}, ${inferredProperties.imageUrl}, 'N/A')}`,
1386
- $when: `\${${inferredProperties.imageUrl} != null}`,
1563
+ $when: `\${${inferredProperties.imageUrl} != null && ${inferredProperties.imageUrl} != ''}`,
1387
1564
  };
1388
1565
  }
1389
1566
  return result;
@@ -1528,6 +1705,7 @@ class ManifestUpdater {
1528
1705
  const confirmationBodies = [];
1529
1706
  if (operationItem) {
1530
1707
  const operationId = operationItem.operationId;
1708
+ const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
1531
1709
  const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1532
1710
  const summary = operationItem.summary;
1533
1711
  const paramObject = operationItem.parameters;
@@ -1555,7 +1733,7 @@ class ManifestUpdater {
1555
1733
  }
1556
1734
  }
1557
1735
  const funcObj = {
1558
- name: operationId,
1736
+ name: safeFunctionName,
1559
1737
  description: description,
1560
1738
  };
1561
1739
  if (options.allowResponseSemantics) {
@@ -1563,7 +1741,7 @@ class ManifestUpdater {
1563
1741
  const { json } = Utils.getResponseJson(operationItem);
1564
1742
  if (json.schema) {
1565
1743
  const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem);
1566
- card.body = card.body.slice(0, 5);
1744
+ card.body = Utils.limitACBodyProperties(card.body, 5);
1567
1745
  const responseSemantic = wrapResponseSemantics(card, jsonPath);
1568
1746
  funcObj.capabilities = {
1569
1747
  response_semantics: responseSemantic,
@@ -1591,7 +1769,7 @@ class ManifestUpdater {
1591
1769
  }
1592
1770
  }
1593
1771
  functions.push(funcObj);
1594
- functionNames.push(operationId);
1772
+ functionNames.push(safeFunctionName);
1595
1773
  const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
1596
1774
  if (conversationStarterStr) {
1597
1775
  conversationStarters.push(conversationStarterStr);
@@ -1929,19 +2107,36 @@ class SpecParser {
1929
2107
  isValid: isValid,
1930
2108
  reason: reason,
1931
2109
  };
1932
- if (isValid) {
2110
+ // Try best to parse server url and auth type
2111
+ try {
1933
2112
  const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
1934
2113
  if (serverObj) {
1935
2114
  apiResult.server = serverObj.url;
1936
2115
  }
2116
+ }
2117
+ catch (err) {
2118
+ // ignore
2119
+ }
2120
+ try {
1937
2121
  const authArray = Utils.getAuthArray(operation.security, spec);
1938
- for (const auths of authArray) {
1939
- if (auths.length === 1) {
1940
- apiResult.auth = auths[0];
1941
- break;
2122
+ if (authArray.length !== 0) {
2123
+ for (const auths of authArray) {
2124
+ if (auths.length === 1) {
2125
+ apiResult.auth = auths[0];
2126
+ break;
2127
+ }
2128
+ else {
2129
+ apiResult.auth = {
2130
+ authScheme: { type: "multipleAuth" },
2131
+ name: auths.map((auth) => auth.name).join(", "),
2132
+ };
2133
+ }
1942
2134
  }
1943
2135
  }
1944
2136
  }
2137
+ catch (err) {
2138
+ // ignore
2139
+ }
1945
2140
  result.APIs.push(apiResult);
1946
2141
  }
1947
2142
  result.allAPICount = result.APIs.length;
@@ -2052,10 +2247,11 @@ class SpecParser {
2052
2247
  const operation = newSpec.paths[url][method];
2053
2248
  try {
2054
2249
  const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
2055
- const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
2250
+ const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
2251
+ const fileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
2056
2252
  const wrappedCard = wrapAdaptiveCard(card, jsonPath);
2057
2253
  yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
2058
- const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
2254
+ const dataFileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
2059
2255
  yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
2060
2256
  }
2061
2257
  catch (err) {