@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.
- package/dist/index.esm2017.js +24 -2
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +210 -14
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +24 -2
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +210 -14
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/interfaces.d.ts +7 -3
- package/dist/src/specOptimizer.d.ts +18 -0
- package/dist/src/utils.d.ts +5 -4
- package/package.json +3 -3
package/dist/index.node.cjs.js
CHANGED
|
@@ -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:
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
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
|
|
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, `${
|
|
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) {
|