@microsoft/m365-spec-parser 0.2.2-alpha.ca8431921.0 → 0.2.2-alpha.cf496ce62.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.
@@ -1105,6 +1105,161 @@ class ValidatorFactory {
1105
1105
  }
1106
1106
  }
1107
1107
 
1108
+ // Copyright (c) Microsoft Corporation.
1109
+ class SpecOptimizer {
1110
+ static optimize(spec, options) {
1111
+ const mergedOptions = Object.assign(Object.assign({}, SpecOptimizer.defaultOptions), (options !== null && options !== void 0 ? options : {}));
1112
+ const newSpec = JSON.parse(JSON.stringify(spec));
1113
+ if (mergedOptions.removeUserDefinedRootProperty) {
1114
+ SpecOptimizer.removeUserDefinedRootProperty(newSpec);
1115
+ }
1116
+ if (mergedOptions.removeUnusedComponents) {
1117
+ SpecOptimizer.removeUnusedComponents(newSpec);
1118
+ }
1119
+ if (mergedOptions.removeUnusedTags) {
1120
+ SpecOptimizer.removeUnusedTags(newSpec);
1121
+ }
1122
+ if (mergedOptions.removeUnusedSecuritySchemas) {
1123
+ SpecOptimizer.removeUnusedSecuritySchemas(newSpec);
1124
+ }
1125
+ return newSpec;
1126
+ }
1127
+ static removeUnusedSecuritySchemas(spec) {
1128
+ if (!spec.components || !spec.components.securitySchemes) {
1129
+ return;
1130
+ }
1131
+ const usedSecuritySchemas = new Set();
1132
+ for (const pathKey in spec.paths) {
1133
+ for (const methodKey in spec.paths[pathKey]) {
1134
+ const operation = spec.paths[pathKey][methodKey];
1135
+ if (operation.security) {
1136
+ operation.security.forEach((securityReq) => {
1137
+ for (const schemaKey in securityReq) {
1138
+ usedSecuritySchemas.add(schemaKey);
1139
+ }
1140
+ });
1141
+ }
1142
+ }
1143
+ }
1144
+ if (spec.security) {
1145
+ spec.security.forEach((securityReq) => {
1146
+ for (const schemaKey in securityReq) {
1147
+ usedSecuritySchemas.add(schemaKey);
1148
+ }
1149
+ });
1150
+ }
1151
+ for (const schemaKey in spec.components.securitySchemes) {
1152
+ if (!usedSecuritySchemas.has(schemaKey)) {
1153
+ delete spec.components.securitySchemes[schemaKey];
1154
+ }
1155
+ }
1156
+ if (Object.keys(spec.components.securitySchemes).length === 0) {
1157
+ delete spec.components.securitySchemes;
1158
+ }
1159
+ if (Object.keys(spec.components).length === 0) {
1160
+ delete spec.components;
1161
+ }
1162
+ }
1163
+ static removeUnusedTags(spec) {
1164
+ if (!spec.tags) {
1165
+ return;
1166
+ }
1167
+ const usedTags = new Set();
1168
+ for (const pathKey in spec.paths) {
1169
+ for (const methodKey in spec.paths[pathKey]) {
1170
+ const operation = spec.paths[pathKey][methodKey];
1171
+ if (operation.tags) {
1172
+ operation.tags.forEach((tag) => usedTags.add(tag));
1173
+ }
1174
+ }
1175
+ }
1176
+ spec.tags = spec.tags.filter((tagObj) => usedTags.has(tagObj.name));
1177
+ }
1178
+ static removeUserDefinedRootProperty(spec) {
1179
+ for (const key in spec) {
1180
+ if (key.startsWith("x-")) {
1181
+ delete spec[key];
1182
+ }
1183
+ }
1184
+ }
1185
+ static removeUnusedComponents(spec) {
1186
+ const components = spec.components;
1187
+ if (!components) {
1188
+ return;
1189
+ }
1190
+ delete spec.components;
1191
+ const usedComponentsSet = new Set();
1192
+ const specString = JSON.stringify(spec);
1193
+ const componentReferences = SpecOptimizer.getComponentReferences(specString);
1194
+ for (const reference of componentReferences) {
1195
+ this.addComponent(reference, usedComponentsSet, components);
1196
+ }
1197
+ const newComponents = {};
1198
+ for (const componentName of usedComponentsSet) {
1199
+ const parts = componentName.split("/");
1200
+ const component = this.getComponent(componentName, components);
1201
+ if (component) {
1202
+ let current = newComponents;
1203
+ for (let i = 2; i < parts.length; i++) {
1204
+ if (i === parts.length - 1) {
1205
+ current[parts[i]] = component;
1206
+ }
1207
+ else if (!current[parts[i]]) {
1208
+ current[parts[i]] = {};
1209
+ }
1210
+ current = current[parts[i]];
1211
+ }
1212
+ }
1213
+ }
1214
+ // securitySchemes are referenced directly by name, to void issue, just keep them all and use removeUnusedSecuritySchemas to remove unused ones
1215
+ if (components.securitySchemes) {
1216
+ newComponents.securitySchemes = components.securitySchemes;
1217
+ }
1218
+ if (Object.keys(newComponents).length !== 0) {
1219
+ spec.components = newComponents;
1220
+ }
1221
+ }
1222
+ static getComponentReferences(specString) {
1223
+ const matches = Array.from(specString.matchAll(/['"](#\/components\/.+?)['"]/g));
1224
+ const matchResult = matches.map((match) => match[1]);
1225
+ return matchResult;
1226
+ }
1227
+ static getComponent(componentPath, components) {
1228
+ const parts = componentPath.split("/");
1229
+ let current = components;
1230
+ for (const part of parts) {
1231
+ if (part === "#" || part === "components") {
1232
+ continue;
1233
+ }
1234
+ current = current[part];
1235
+ if (!current) {
1236
+ return null;
1237
+ }
1238
+ }
1239
+ return current;
1240
+ }
1241
+ static addComponent(componentName, usedComponentsSet, components) {
1242
+ if (usedComponentsSet.has(componentName)) {
1243
+ return;
1244
+ }
1245
+ usedComponentsSet.add(componentName);
1246
+ const component = this.getComponent(componentName, components);
1247
+ if (component) {
1248
+ const componentString = JSON.stringify(component);
1249
+ const componentReferences = SpecOptimizer.getComponentReferences(componentString);
1250
+ for (const reference of componentReferences) {
1251
+ this.addComponent(reference, usedComponentsSet, components);
1252
+ }
1253
+ }
1254
+ }
1255
+ }
1256
+ SpecOptimizer.defaultOptions = {
1257
+ removeUnusedComponents: true,
1258
+ removeUnusedTags: true,
1259
+ removeUserDefinedRootProperty: true,
1260
+ removeUnusedSecuritySchemas: true,
1261
+ };
1262
+
1108
1263
  // Copyright (c) Microsoft Corporation.
1109
1264
  class SpecFilter {
1110
1265
  static specFilter(filter, unResolveSpec, resolvedSpec, options) {
@@ -1138,7 +1293,7 @@ class SpecFilter {
1138
1293
  }
1139
1294
  }
1140
1295
  newSpec.paths = newPaths;
1141
- return newSpec;
1296
+ return SpecOptimizer.optimize(newSpec);
1142
1297
  }
1143
1298
  catch (err) {
1144
1299
  throw new SpecParserError(err.toString(), ErrorType.FilterSpecFailed);
@@ -1261,7 +1416,7 @@ class AdaptiveCardGenerator {
1261
1416
  {
1262
1417
  type: "Image",
1263
1418
  url: `\${${name}}`,
1264
- $when: `\${${name} != null}`,
1419
+ $when: `\${${name} != null && ${name} != ''}`,
1265
1420
  },
1266
1421
  ];
1267
1422
  }
@@ -1270,7 +1425,7 @@ class AdaptiveCardGenerator {
1270
1425
  {
1271
1426
  type: "Image",
1272
1427
  url: "${$data}",
1273
- $when: "${$data != null}",
1428
+ $when: "${$data != null && $data != ''}",
1274
1429
  },
1275
1430
  ];
1276
1431
  }
@@ -1363,7 +1518,7 @@ function inferPreviewCardTemplate(card) {
1363
1518
  result.image = {
1364
1519
  url: `\${${inferredProperties.imageUrl}}`,
1365
1520
  alt: `\${if(${inferredProperties.imageUrl}, ${inferredProperties.imageUrl}, 'N/A')}`,
1366
- $when: `\${${inferredProperties.imageUrl} != null}`,
1521
+ $when: `\${${inferredProperties.imageUrl} != null && ${inferredProperties.imageUrl} != ''}`,
1367
1522
  };
1368
1523
  }
1369
1524
  return result;