@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.esm2017.mjs
CHANGED
|
@@ -536,6 +536,28 @@ class Utils {
|
|
|
536
536
|
const serverUrl = operationServer || methodServer || rootServer;
|
|
537
537
|
return serverUrl;
|
|
538
538
|
}
|
|
539
|
+
static limitACBodyProperties(body, maxCount) {
|
|
540
|
+
const result = [];
|
|
541
|
+
let currentCount = 0;
|
|
542
|
+
for (const element of body) {
|
|
543
|
+
if (element.type === ConstantString.ContainerType) {
|
|
544
|
+
const items = this.limitACBodyProperties(element.items, maxCount - currentCount);
|
|
545
|
+
result.push({
|
|
546
|
+
type: ConstantString.ContainerType,
|
|
547
|
+
$data: element.$data,
|
|
548
|
+
items: items,
|
|
549
|
+
});
|
|
550
|
+
currentCount += items.length;
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
if (currentCount < maxCount) {
|
|
554
|
+
result.push(element);
|
|
555
|
+
currentCount++;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return result;
|
|
560
|
+
}
|
|
539
561
|
}
|
|
540
562
|
|
|
541
563
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -1083,6 +1105,161 @@ class ValidatorFactory {
|
|
|
1083
1105
|
}
|
|
1084
1106
|
}
|
|
1085
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
|
+
|
|
1086
1263
|
// Copyright (c) Microsoft Corporation.
|
|
1087
1264
|
class SpecFilter {
|
|
1088
1265
|
static specFilter(filter, unResolveSpec, resolvedSpec, options) {
|
|
@@ -1116,7 +1293,7 @@ class SpecFilter {
|
|
|
1116
1293
|
}
|
|
1117
1294
|
}
|
|
1118
1295
|
newSpec.paths = newPaths;
|
|
1119
|
-
return newSpec;
|
|
1296
|
+
return SpecOptimizer.optimize(newSpec);
|
|
1120
1297
|
}
|
|
1121
1298
|
catch (err) {
|
|
1122
1299
|
throw new SpecParserError(err.toString(), ErrorType.FilterSpecFailed);
|
|
@@ -1239,7 +1416,7 @@ class AdaptiveCardGenerator {
|
|
|
1239
1416
|
{
|
|
1240
1417
|
type: "Image",
|
|
1241
1418
|
url: `\${${name}}`,
|
|
1242
|
-
$when: `\${${name} != null}`,
|
|
1419
|
+
$when: `\${${name} != null && ${name} != ''}`,
|
|
1243
1420
|
},
|
|
1244
1421
|
];
|
|
1245
1422
|
}
|
|
@@ -1248,7 +1425,7 @@ class AdaptiveCardGenerator {
|
|
|
1248
1425
|
{
|
|
1249
1426
|
type: "Image",
|
|
1250
1427
|
url: "${$data}",
|
|
1251
|
-
$when: "${$data != null}",
|
|
1428
|
+
$when: "${$data != null && $data != ''}",
|
|
1252
1429
|
},
|
|
1253
1430
|
];
|
|
1254
1431
|
}
|
|
@@ -1341,7 +1518,7 @@ function inferPreviewCardTemplate(card) {
|
|
|
1341
1518
|
result.image = {
|
|
1342
1519
|
url: `\${${inferredProperties.imageUrl}}`,
|
|
1343
1520
|
alt: `\${if(${inferredProperties.imageUrl}, ${inferredProperties.imageUrl}, 'N/A')}`,
|
|
1344
|
-
$when: `\${${inferredProperties.imageUrl} != null}`,
|
|
1521
|
+
$when: `\${${inferredProperties.imageUrl} != null && ${inferredProperties.imageUrl} != ''}`,
|
|
1345
1522
|
};
|
|
1346
1523
|
}
|
|
1347
1524
|
return result;
|
|
@@ -1483,6 +1660,7 @@ class ManifestUpdater {
|
|
|
1483
1660
|
const confirmationBodies = [];
|
|
1484
1661
|
if (operationItem) {
|
|
1485
1662
|
const operationId = operationItem.operationId;
|
|
1663
|
+
const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1486
1664
|
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
1487
1665
|
const summary = operationItem.summary;
|
|
1488
1666
|
const paramObject = operationItem.parameters;
|
|
@@ -1510,7 +1688,7 @@ class ManifestUpdater {
|
|
|
1510
1688
|
}
|
|
1511
1689
|
}
|
|
1512
1690
|
const funcObj = {
|
|
1513
|
-
name:
|
|
1691
|
+
name: safeFunctionName,
|
|
1514
1692
|
description: description,
|
|
1515
1693
|
};
|
|
1516
1694
|
if (options.allowResponseSemantics) {
|
|
@@ -1518,7 +1696,7 @@ class ManifestUpdater {
|
|
|
1518
1696
|
const { json } = Utils.getResponseJson(operationItem);
|
|
1519
1697
|
if (json.schema) {
|
|
1520
1698
|
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem);
|
|
1521
|
-
card.body = card.body
|
|
1699
|
+
card.body = Utils.limitACBodyProperties(card.body, 5);
|
|
1522
1700
|
const responseSemantic = wrapResponseSemantics(card, jsonPath);
|
|
1523
1701
|
funcObj.capabilities = {
|
|
1524
1702
|
response_semantics: responseSemantic,
|
|
@@ -1546,7 +1724,7 @@ class ManifestUpdater {
|
|
|
1546
1724
|
}
|
|
1547
1725
|
}
|
|
1548
1726
|
functions.push(funcObj);
|
|
1549
|
-
functionNames.push(
|
|
1727
|
+
functionNames.push(safeFunctionName);
|
|
1550
1728
|
const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
|
|
1551
1729
|
if (conversationStarterStr) {
|
|
1552
1730
|
conversationStarters.push(conversationStarterStr);
|
|
@@ -1874,19 +2052,36 @@ class SpecParser {
|
|
|
1874
2052
|
isValid: isValid,
|
|
1875
2053
|
reason: reason,
|
|
1876
2054
|
};
|
|
1877
|
-
|
|
2055
|
+
// Try best to parse server url and auth type
|
|
2056
|
+
try {
|
|
1878
2057
|
const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
|
|
1879
2058
|
if (serverObj) {
|
|
1880
2059
|
apiResult.server = serverObj.url;
|
|
1881
2060
|
}
|
|
2061
|
+
}
|
|
2062
|
+
catch (err) {
|
|
2063
|
+
// ignore
|
|
2064
|
+
}
|
|
2065
|
+
try {
|
|
1882
2066
|
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
2067
|
+
if (authArray.length !== 0) {
|
|
2068
|
+
for (const auths of authArray) {
|
|
2069
|
+
if (auths.length === 1) {
|
|
2070
|
+
apiResult.auth = auths[0];
|
|
2071
|
+
break;
|
|
2072
|
+
}
|
|
2073
|
+
else {
|
|
2074
|
+
apiResult.auth = {
|
|
2075
|
+
authScheme: { type: "multipleAuth" },
|
|
2076
|
+
name: auths.map((auth) => auth.name).join(", "),
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
1887
2079
|
}
|
|
1888
2080
|
}
|
|
1889
2081
|
}
|
|
2082
|
+
catch (err) {
|
|
2083
|
+
// ignore
|
|
2084
|
+
}
|
|
1890
2085
|
result.APIs.push(apiResult);
|
|
1891
2086
|
}
|
|
1892
2087
|
result.allAPICount = result.APIs.length;
|
|
@@ -1991,10 +2186,11 @@ class SpecParser {
|
|
|
1991
2186
|
const operation = newSpec.paths[url][method];
|
|
1992
2187
|
try {
|
|
1993
2188
|
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
1994
|
-
const
|
|
2189
|
+
const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2190
|
+
const fileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
|
|
1995
2191
|
const wrappedCard = wrapAdaptiveCard(card, jsonPath);
|
|
1996
2192
|
await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
|
|
1997
|
-
const dataFileName = path.join(adaptiveCardFolder, `${
|
|
2193
|
+
const dataFileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
|
|
1998
2194
|
await fs.outputJSON(dataFileName, {}, { spaces: 2 });
|
|
1999
2195
|
}
|
|
2000
2196
|
catch (err) {
|