@microsoft/m365-spec-parser 0.2.2-alpha.5c16a1140.0 → 0.2.2-alpha.5d0324fcc.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 +26 -17
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +203 -22
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +26 -17
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +203 -22
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +2 -0
- package/dist/src/interfaces.d.ts +1 -0
- package/dist/src/specOptimizer.d.ts +18 -0
- package/dist/src/specParser.d.ts +1 -1
- package/package.json +3 -3
package/dist/index.node.cjs.js
CHANGED
|
@@ -100,6 +100,7 @@ exports.WarningType = void 0;
|
|
|
100
100
|
WarningType["GenerateCardFailed"] = "generate-card-failed";
|
|
101
101
|
WarningType["OperationOnlyContainsOptionalParam"] = "operation-only-contains-optional-param";
|
|
102
102
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
103
|
+
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
103
104
|
WarningType["Unknown"] = "unknown";
|
|
104
105
|
})(exports.WarningType || (exports.WarningType = {}));
|
|
105
106
|
/**
|
|
@@ -138,6 +139,7 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
|
|
|
138
139
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
139
140
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
140
141
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
142
|
+
ConstantString.FuncDescriptionTooLong = "The description of the function '%s' is too long. The current length is %s characters, while the maximum allowed length is %s characters.";
|
|
141
143
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
142
144
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
143
145
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
@@ -217,6 +219,7 @@ ConstantString.ConversationStarterMaxLens = 50;
|
|
|
217
219
|
ConstantString.CommandTitleMaxLens = 32;
|
|
218
220
|
ConstantString.ParameterTitleMaxLens = 32;
|
|
219
221
|
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
222
|
+
ConstantString.FunctionDescriptionMaxLens = 100;
|
|
220
223
|
ConstantString.DefaultPluginId = "plugin_1";
|
|
221
224
|
ConstantString.PluginManifestSchema = "https://aka.ms/json-schemas/copilot-extensions/v2.1/plugin.schema.json";
|
|
222
225
|
|
|
@@ -302,23 +305,28 @@ class Utils {
|
|
|
302
305
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
303
306
|
}
|
|
304
307
|
static getResponseJson(operationObject, allowMultipleMediaType = false) {
|
|
305
|
-
var _a
|
|
308
|
+
var _a;
|
|
306
309
|
let json = {};
|
|
307
310
|
let multipleMediaType = false;
|
|
308
311
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
309
312
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
310
|
-
if (
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
313
|
+
if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
|
|
314
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
315
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
316
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
317
|
+
multipleMediaType = false;
|
|
318
|
+
json = responseObject.content[contentType];
|
|
319
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
320
|
+
multipleMediaType = true;
|
|
321
|
+
if (!allowMultipleMediaType) {
|
|
322
|
+
json = {};
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
return { json, multipleMediaType };
|
|
327
|
+
}
|
|
317
328
|
}
|
|
318
329
|
}
|
|
319
|
-
else {
|
|
320
|
-
break;
|
|
321
|
-
}
|
|
322
330
|
}
|
|
323
331
|
}
|
|
324
332
|
return { json, multipleMediaType };
|
|
@@ -592,10 +600,11 @@ class Utils {
|
|
|
592
600
|
currentCount += items.length;
|
|
593
601
|
}
|
|
594
602
|
else {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
603
|
+
result.push(element);
|
|
604
|
+
currentCount++;
|
|
605
|
+
}
|
|
606
|
+
if (currentCount >= maxCount) {
|
|
607
|
+
break;
|
|
599
608
|
}
|
|
600
609
|
}
|
|
601
610
|
return result;
|
|
@@ -1147,6 +1156,161 @@ class ValidatorFactory {
|
|
|
1147
1156
|
}
|
|
1148
1157
|
}
|
|
1149
1158
|
|
|
1159
|
+
// Copyright (c) Microsoft Corporation.
|
|
1160
|
+
class SpecOptimizer {
|
|
1161
|
+
static optimize(spec, options) {
|
|
1162
|
+
const mergedOptions = Object.assign(Object.assign({}, SpecOptimizer.defaultOptions), (options !== null && options !== void 0 ? options : {}));
|
|
1163
|
+
const newSpec = JSON.parse(JSON.stringify(spec));
|
|
1164
|
+
if (mergedOptions.removeUserDefinedRootProperty) {
|
|
1165
|
+
SpecOptimizer.removeUserDefinedRootProperty(newSpec);
|
|
1166
|
+
}
|
|
1167
|
+
if (mergedOptions.removeUnusedComponents) {
|
|
1168
|
+
SpecOptimizer.removeUnusedComponents(newSpec);
|
|
1169
|
+
}
|
|
1170
|
+
if (mergedOptions.removeUnusedTags) {
|
|
1171
|
+
SpecOptimizer.removeUnusedTags(newSpec);
|
|
1172
|
+
}
|
|
1173
|
+
if (mergedOptions.removeUnusedSecuritySchemas) {
|
|
1174
|
+
SpecOptimizer.removeUnusedSecuritySchemas(newSpec);
|
|
1175
|
+
}
|
|
1176
|
+
return newSpec;
|
|
1177
|
+
}
|
|
1178
|
+
static removeUnusedSecuritySchemas(spec) {
|
|
1179
|
+
if (!spec.components || !spec.components.securitySchemes) {
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
const usedSecuritySchemas = new Set();
|
|
1183
|
+
for (const pathKey in spec.paths) {
|
|
1184
|
+
for (const methodKey in spec.paths[pathKey]) {
|
|
1185
|
+
const operation = spec.paths[pathKey][methodKey];
|
|
1186
|
+
if (operation.security) {
|
|
1187
|
+
operation.security.forEach((securityReq) => {
|
|
1188
|
+
for (const schemaKey in securityReq) {
|
|
1189
|
+
usedSecuritySchemas.add(schemaKey);
|
|
1190
|
+
}
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (spec.security) {
|
|
1196
|
+
spec.security.forEach((securityReq) => {
|
|
1197
|
+
for (const schemaKey in securityReq) {
|
|
1198
|
+
usedSecuritySchemas.add(schemaKey);
|
|
1199
|
+
}
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
for (const schemaKey in spec.components.securitySchemes) {
|
|
1203
|
+
if (!usedSecuritySchemas.has(schemaKey)) {
|
|
1204
|
+
delete spec.components.securitySchemes[schemaKey];
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
if (Object.keys(spec.components.securitySchemes).length === 0) {
|
|
1208
|
+
delete spec.components.securitySchemes;
|
|
1209
|
+
}
|
|
1210
|
+
if (Object.keys(spec.components).length === 0) {
|
|
1211
|
+
delete spec.components;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
static removeUnusedTags(spec) {
|
|
1215
|
+
if (!spec.tags) {
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
const usedTags = new Set();
|
|
1219
|
+
for (const pathKey in spec.paths) {
|
|
1220
|
+
for (const methodKey in spec.paths[pathKey]) {
|
|
1221
|
+
const operation = spec.paths[pathKey][methodKey];
|
|
1222
|
+
if (operation.tags) {
|
|
1223
|
+
operation.tags.forEach((tag) => usedTags.add(tag));
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
spec.tags = spec.tags.filter((tagObj) => usedTags.has(tagObj.name));
|
|
1228
|
+
}
|
|
1229
|
+
static removeUserDefinedRootProperty(spec) {
|
|
1230
|
+
for (const key in spec) {
|
|
1231
|
+
if (key.startsWith("x-")) {
|
|
1232
|
+
delete spec[key];
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
static removeUnusedComponents(spec) {
|
|
1237
|
+
const components = spec.components;
|
|
1238
|
+
if (!components) {
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
delete spec.components;
|
|
1242
|
+
const usedComponentsSet = new Set();
|
|
1243
|
+
const specString = JSON.stringify(spec);
|
|
1244
|
+
const componentReferences = SpecOptimizer.getComponentReferences(specString);
|
|
1245
|
+
for (const reference of componentReferences) {
|
|
1246
|
+
this.addComponent(reference, usedComponentsSet, components);
|
|
1247
|
+
}
|
|
1248
|
+
const newComponents = {};
|
|
1249
|
+
for (const componentName of usedComponentsSet) {
|
|
1250
|
+
const parts = componentName.split("/");
|
|
1251
|
+
const component = this.getComponent(componentName, components);
|
|
1252
|
+
if (component) {
|
|
1253
|
+
let current = newComponents;
|
|
1254
|
+
for (let i = 2; i < parts.length; i++) {
|
|
1255
|
+
if (i === parts.length - 1) {
|
|
1256
|
+
current[parts[i]] = component;
|
|
1257
|
+
}
|
|
1258
|
+
else if (!current[parts[i]]) {
|
|
1259
|
+
current[parts[i]] = {};
|
|
1260
|
+
}
|
|
1261
|
+
current = current[parts[i]];
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
// securitySchemes are referenced directly by name, to void issue, just keep them all and use removeUnusedSecuritySchemas to remove unused ones
|
|
1266
|
+
if (components.securitySchemes) {
|
|
1267
|
+
newComponents.securitySchemes = components.securitySchemes;
|
|
1268
|
+
}
|
|
1269
|
+
if (Object.keys(newComponents).length !== 0) {
|
|
1270
|
+
spec.components = newComponents;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
static getComponentReferences(specString) {
|
|
1274
|
+
const matches = Array.from(specString.matchAll(/['"](#\/components\/.+?)['"]/g));
|
|
1275
|
+
const matchResult = matches.map((match) => match[1]);
|
|
1276
|
+
return matchResult;
|
|
1277
|
+
}
|
|
1278
|
+
static getComponent(componentPath, components) {
|
|
1279
|
+
const parts = componentPath.split("/");
|
|
1280
|
+
let current = components;
|
|
1281
|
+
for (const part of parts) {
|
|
1282
|
+
if (part === "#" || part === "components") {
|
|
1283
|
+
continue;
|
|
1284
|
+
}
|
|
1285
|
+
current = current[part];
|
|
1286
|
+
if (!current) {
|
|
1287
|
+
return null;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
return current;
|
|
1291
|
+
}
|
|
1292
|
+
static addComponent(componentName, usedComponentsSet, components) {
|
|
1293
|
+
if (usedComponentsSet.has(componentName)) {
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
usedComponentsSet.add(componentName);
|
|
1297
|
+
const component = this.getComponent(componentName, components);
|
|
1298
|
+
if (component) {
|
|
1299
|
+
const componentString = JSON.stringify(component);
|
|
1300
|
+
const componentReferences = SpecOptimizer.getComponentReferences(componentString);
|
|
1301
|
+
for (const reference of componentReferences) {
|
|
1302
|
+
this.addComponent(reference, usedComponentsSet, components);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
SpecOptimizer.defaultOptions = {
|
|
1308
|
+
removeUnusedComponents: true,
|
|
1309
|
+
removeUnusedTags: true,
|
|
1310
|
+
removeUserDefinedRootProperty: true,
|
|
1311
|
+
removeUnusedSecuritySchemas: true,
|
|
1312
|
+
};
|
|
1313
|
+
|
|
1150
1314
|
// Copyright (c) Microsoft Corporation.
|
|
1151
1315
|
class SpecFilter {
|
|
1152
1316
|
static specFilter(filter, unResolveSpec, resolvedSpec, options) {
|
|
@@ -1180,7 +1344,7 @@ class SpecFilter {
|
|
|
1180
1344
|
}
|
|
1181
1345
|
}
|
|
1182
1346
|
newSpec.paths = newPaths;
|
|
1183
|
-
return newSpec;
|
|
1347
|
+
return SpecOptimizer.optimize(newSpec);
|
|
1184
1348
|
}
|
|
1185
1349
|
catch (err) {
|
|
1186
1350
|
throw new SpecParserError(err.toString(), exports.ErrorType.FilterSpecFailed);
|
|
@@ -1303,7 +1467,7 @@ class AdaptiveCardGenerator {
|
|
|
1303
1467
|
{
|
|
1304
1468
|
type: "Image",
|
|
1305
1469
|
url: `\${${name}}`,
|
|
1306
|
-
$when: `\${${name} != null}`,
|
|
1470
|
+
$when: `\${${name} != null && ${name} != ''}`,
|
|
1307
1471
|
},
|
|
1308
1472
|
];
|
|
1309
1473
|
}
|
|
@@ -1312,7 +1476,7 @@ class AdaptiveCardGenerator {
|
|
|
1312
1476
|
{
|
|
1313
1477
|
type: "Image",
|
|
1314
1478
|
url: "${$data}",
|
|
1315
|
-
$when: "${$data != null}",
|
|
1479
|
+
$when: "${$data != null && $data != ''}",
|
|
1316
1480
|
},
|
|
1317
1481
|
];
|
|
1318
1482
|
}
|
|
@@ -1405,7 +1569,7 @@ function inferPreviewCardTemplate(card) {
|
|
|
1405
1569
|
result.image = {
|
|
1406
1570
|
url: `\${${inferredProperties.imageUrl}}`,
|
|
1407
1571
|
alt: `\${if(${inferredProperties.imageUrl}, ${inferredProperties.imageUrl}, 'N/A')}`,
|
|
1408
|
-
$when: `\${${inferredProperties.imageUrl} != null}`,
|
|
1572
|
+
$when: `\${${inferredProperties.imageUrl} != null && ${inferredProperties.imageUrl} != ''}`,
|
|
1409
1573
|
};
|
|
1410
1574
|
}
|
|
1411
1575
|
return result;
|
|
@@ -1577,9 +1741,18 @@ class ManifestUpdater {
|
|
|
1577
1741
|
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), exports.ErrorType.UpdateManifestFailed);
|
|
1578
1742
|
}
|
|
1579
1743
|
}
|
|
1744
|
+
let funcDescription = operationItem.description || operationItem.summary || "";
|
|
1745
|
+
if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
|
|
1746
|
+
warnings.push({
|
|
1747
|
+
type: exports.WarningType.FuncDescriptionTooLong,
|
|
1748
|
+
content: Utils.format(ConstantString.FuncDescriptionTooLong, safeFunctionName, funcDescription.length.toString(), ConstantString.FunctionDescriptionMaxLens.toString()),
|
|
1749
|
+
data: safeFunctionName,
|
|
1750
|
+
});
|
|
1751
|
+
funcDescription = funcDescription.slice(0, ConstantString.FunctionDescriptionMaxLens);
|
|
1752
|
+
}
|
|
1580
1753
|
const funcObj = {
|
|
1581
1754
|
name: safeFunctionName,
|
|
1582
|
-
description:
|
|
1755
|
+
description: funcDescription,
|
|
1583
1756
|
};
|
|
1584
1757
|
if (options.allowResponseSemantics) {
|
|
1585
1758
|
try {
|
|
@@ -2033,7 +2206,7 @@ class SpecParser {
|
|
|
2033
2206
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
2034
2207
|
* @param pluginFilePath File path of the api plugin file to generate.
|
|
2035
2208
|
*/
|
|
2036
|
-
generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
2209
|
+
generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, existingPluginFilePath, signal) {
|
|
2037
2210
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2038
2211
|
const result = {
|
|
2039
2212
|
allSuccess: true,
|
|
@@ -2051,7 +2224,15 @@ class SpecParser {
|
|
|
2051
2224
|
const [updatedManifest, apiPlugin, warnings] = yield ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authInfo);
|
|
2052
2225
|
result.warnings.push(...warnings);
|
|
2053
2226
|
yield fs__default['default'].outputJSON(manifestPath, updatedManifest, { spaces: 4 });
|
|
2054
|
-
|
|
2227
|
+
if (existingPluginFilePath) {
|
|
2228
|
+
const originPluginManifest = (yield fs__default['default'].readJSON(existingPluginFilePath));
|
|
2229
|
+
// TODO (kiota): refactor to avoid generate apiPlugin
|
|
2230
|
+
originPluginManifest.functions = apiPlugin.functions;
|
|
2231
|
+
yield fs__default['default'].outputJSON(pluginFilePath, originPluginManifest, { spaces: 4 });
|
|
2232
|
+
}
|
|
2233
|
+
else {
|
|
2234
|
+
yield fs__default['default'].outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
|
|
2235
|
+
}
|
|
2055
2236
|
}
|
|
2056
2237
|
catch (err) {
|
|
2057
2238
|
if (err instanceof SpecParserError) {
|