@microsoft/m365-spec-parser 0.2.2-alpha.ca8431921.0 → 0.2.2-alpha.db6b164d0.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.
@@ -1147,6 +1147,161 @@ class ValidatorFactory {
1147
1147
  }
1148
1148
  }
1149
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
+
1150
1305
  // Copyright (c) Microsoft Corporation.
1151
1306
  class SpecFilter {
1152
1307
  static specFilter(filter, unResolveSpec, resolvedSpec, options) {
@@ -1180,7 +1335,7 @@ class SpecFilter {
1180
1335
  }
1181
1336
  }
1182
1337
  newSpec.paths = newPaths;
1183
- return newSpec;
1338
+ return SpecOptimizer.optimize(newSpec);
1184
1339
  }
1185
1340
  catch (err) {
1186
1341
  throw new SpecParserError(err.toString(), exports.ErrorType.FilterSpecFailed);
@@ -1303,7 +1458,7 @@ class AdaptiveCardGenerator {
1303
1458
  {
1304
1459
  type: "Image",
1305
1460
  url: `\${${name}}`,
1306
- $when: `\${${name} != null}`,
1461
+ $when: `\${${name} != null && ${name} != ''}`,
1307
1462
  },
1308
1463
  ];
1309
1464
  }
@@ -1312,7 +1467,7 @@ class AdaptiveCardGenerator {
1312
1467
  {
1313
1468
  type: "Image",
1314
1469
  url: "${$data}",
1315
- $when: "${$data != null}",
1470
+ $when: "${$data != null && $data != ''}",
1316
1471
  },
1317
1472
  ];
1318
1473
  }
@@ -1405,7 +1560,7 @@ function inferPreviewCardTemplate(card) {
1405
1560
  result.image = {
1406
1561
  url: `\${${inferredProperties.imageUrl}}`,
1407
1562
  alt: `\${if(${inferredProperties.imageUrl}, ${inferredProperties.imageUrl}, 'N/A')}`,
1408
- $when: `\${${inferredProperties.imageUrl} != null}`,
1563
+ $when: `\${${inferredProperties.imageUrl} != null && ${inferredProperties.imageUrl} != ''}`,
1409
1564
  };
1410
1565
  }
1411
1566
  return result;