@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.esm2017.mjs
CHANGED
|
@@ -58,6 +58,7 @@ var WarningType;
|
|
|
58
58
|
WarningType["GenerateCardFailed"] = "generate-card-failed";
|
|
59
59
|
WarningType["OperationOnlyContainsOptionalParam"] = "operation-only-contains-optional-param";
|
|
60
60
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
61
|
+
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
61
62
|
WarningType["Unknown"] = "unknown";
|
|
62
63
|
})(WarningType || (WarningType = {}));
|
|
63
64
|
/**
|
|
@@ -96,6 +97,7 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
|
|
|
96
97
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
97
98
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
98
99
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
100
|
+
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.";
|
|
99
101
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
100
102
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
101
103
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
@@ -175,6 +177,7 @@ ConstantString.ConversationStarterMaxLens = 50;
|
|
|
175
177
|
ConstantString.CommandTitleMaxLens = 32;
|
|
176
178
|
ConstantString.ParameterTitleMaxLens = 32;
|
|
177
179
|
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
180
|
+
ConstantString.FunctionDescriptionMaxLens = 100;
|
|
178
181
|
ConstantString.DefaultPluginId = "plugin_1";
|
|
179
182
|
ConstantString.PluginManifestSchema = "https://aka.ms/json-schemas/copilot-extensions/v2.1/plugin.schema.json";
|
|
180
183
|
|
|
@@ -260,23 +263,28 @@ class Utils {
|
|
|
260
263
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
261
264
|
}
|
|
262
265
|
static getResponseJson(operationObject, allowMultipleMediaType = false) {
|
|
263
|
-
var _a
|
|
266
|
+
var _a;
|
|
264
267
|
let json = {};
|
|
265
268
|
let multipleMediaType = false;
|
|
266
269
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
267
270
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
271
|
+
if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
|
|
272
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
273
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
274
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
275
|
+
multipleMediaType = false;
|
|
276
|
+
json = responseObject.content[contentType];
|
|
277
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
278
|
+
multipleMediaType = true;
|
|
279
|
+
if (!allowMultipleMediaType) {
|
|
280
|
+
json = {};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
return { json, multipleMediaType };
|
|
285
|
+
}
|
|
275
286
|
}
|
|
276
287
|
}
|
|
277
|
-
else {
|
|
278
|
-
break;
|
|
279
|
-
}
|
|
280
288
|
}
|
|
281
289
|
}
|
|
282
290
|
return { json, multipleMediaType };
|
|
@@ -550,10 +558,11 @@ class Utils {
|
|
|
550
558
|
currentCount += items.length;
|
|
551
559
|
}
|
|
552
560
|
else {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
561
|
+
result.push(element);
|
|
562
|
+
currentCount++;
|
|
563
|
+
}
|
|
564
|
+
if (currentCount >= maxCount) {
|
|
565
|
+
break;
|
|
557
566
|
}
|
|
558
567
|
}
|
|
559
568
|
return result;
|
|
@@ -1105,6 +1114,161 @@ class ValidatorFactory {
|
|
|
1105
1114
|
}
|
|
1106
1115
|
}
|
|
1107
1116
|
|
|
1117
|
+
// Copyright (c) Microsoft Corporation.
|
|
1118
|
+
class SpecOptimizer {
|
|
1119
|
+
static optimize(spec, options) {
|
|
1120
|
+
const mergedOptions = Object.assign(Object.assign({}, SpecOptimizer.defaultOptions), (options !== null && options !== void 0 ? options : {}));
|
|
1121
|
+
const newSpec = JSON.parse(JSON.stringify(spec));
|
|
1122
|
+
if (mergedOptions.removeUserDefinedRootProperty) {
|
|
1123
|
+
SpecOptimizer.removeUserDefinedRootProperty(newSpec);
|
|
1124
|
+
}
|
|
1125
|
+
if (mergedOptions.removeUnusedComponents) {
|
|
1126
|
+
SpecOptimizer.removeUnusedComponents(newSpec);
|
|
1127
|
+
}
|
|
1128
|
+
if (mergedOptions.removeUnusedTags) {
|
|
1129
|
+
SpecOptimizer.removeUnusedTags(newSpec);
|
|
1130
|
+
}
|
|
1131
|
+
if (mergedOptions.removeUnusedSecuritySchemas) {
|
|
1132
|
+
SpecOptimizer.removeUnusedSecuritySchemas(newSpec);
|
|
1133
|
+
}
|
|
1134
|
+
return newSpec;
|
|
1135
|
+
}
|
|
1136
|
+
static removeUnusedSecuritySchemas(spec) {
|
|
1137
|
+
if (!spec.components || !spec.components.securitySchemes) {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
const usedSecuritySchemas = new Set();
|
|
1141
|
+
for (const pathKey in spec.paths) {
|
|
1142
|
+
for (const methodKey in spec.paths[pathKey]) {
|
|
1143
|
+
const operation = spec.paths[pathKey][methodKey];
|
|
1144
|
+
if (operation.security) {
|
|
1145
|
+
operation.security.forEach((securityReq) => {
|
|
1146
|
+
for (const schemaKey in securityReq) {
|
|
1147
|
+
usedSecuritySchemas.add(schemaKey);
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
if (spec.security) {
|
|
1154
|
+
spec.security.forEach((securityReq) => {
|
|
1155
|
+
for (const schemaKey in securityReq) {
|
|
1156
|
+
usedSecuritySchemas.add(schemaKey);
|
|
1157
|
+
}
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
for (const schemaKey in spec.components.securitySchemes) {
|
|
1161
|
+
if (!usedSecuritySchemas.has(schemaKey)) {
|
|
1162
|
+
delete spec.components.securitySchemes[schemaKey];
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
if (Object.keys(spec.components.securitySchemes).length === 0) {
|
|
1166
|
+
delete spec.components.securitySchemes;
|
|
1167
|
+
}
|
|
1168
|
+
if (Object.keys(spec.components).length === 0) {
|
|
1169
|
+
delete spec.components;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
static removeUnusedTags(spec) {
|
|
1173
|
+
if (!spec.tags) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
const usedTags = new Set();
|
|
1177
|
+
for (const pathKey in spec.paths) {
|
|
1178
|
+
for (const methodKey in spec.paths[pathKey]) {
|
|
1179
|
+
const operation = spec.paths[pathKey][methodKey];
|
|
1180
|
+
if (operation.tags) {
|
|
1181
|
+
operation.tags.forEach((tag) => usedTags.add(tag));
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
spec.tags = spec.tags.filter((tagObj) => usedTags.has(tagObj.name));
|
|
1186
|
+
}
|
|
1187
|
+
static removeUserDefinedRootProperty(spec) {
|
|
1188
|
+
for (const key in spec) {
|
|
1189
|
+
if (key.startsWith("x-")) {
|
|
1190
|
+
delete spec[key];
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
static removeUnusedComponents(spec) {
|
|
1195
|
+
const components = spec.components;
|
|
1196
|
+
if (!components) {
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
delete spec.components;
|
|
1200
|
+
const usedComponentsSet = new Set();
|
|
1201
|
+
const specString = JSON.stringify(spec);
|
|
1202
|
+
const componentReferences = SpecOptimizer.getComponentReferences(specString);
|
|
1203
|
+
for (const reference of componentReferences) {
|
|
1204
|
+
this.addComponent(reference, usedComponentsSet, components);
|
|
1205
|
+
}
|
|
1206
|
+
const newComponents = {};
|
|
1207
|
+
for (const componentName of usedComponentsSet) {
|
|
1208
|
+
const parts = componentName.split("/");
|
|
1209
|
+
const component = this.getComponent(componentName, components);
|
|
1210
|
+
if (component) {
|
|
1211
|
+
let current = newComponents;
|
|
1212
|
+
for (let i = 2; i < parts.length; i++) {
|
|
1213
|
+
if (i === parts.length - 1) {
|
|
1214
|
+
current[parts[i]] = component;
|
|
1215
|
+
}
|
|
1216
|
+
else if (!current[parts[i]]) {
|
|
1217
|
+
current[parts[i]] = {};
|
|
1218
|
+
}
|
|
1219
|
+
current = current[parts[i]];
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
// securitySchemes are referenced directly by name, to void issue, just keep them all and use removeUnusedSecuritySchemas to remove unused ones
|
|
1224
|
+
if (components.securitySchemes) {
|
|
1225
|
+
newComponents.securitySchemes = components.securitySchemes;
|
|
1226
|
+
}
|
|
1227
|
+
if (Object.keys(newComponents).length !== 0) {
|
|
1228
|
+
spec.components = newComponents;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
static getComponentReferences(specString) {
|
|
1232
|
+
const matches = Array.from(specString.matchAll(/['"](#\/components\/.+?)['"]/g));
|
|
1233
|
+
const matchResult = matches.map((match) => match[1]);
|
|
1234
|
+
return matchResult;
|
|
1235
|
+
}
|
|
1236
|
+
static getComponent(componentPath, components) {
|
|
1237
|
+
const parts = componentPath.split("/");
|
|
1238
|
+
let current = components;
|
|
1239
|
+
for (const part of parts) {
|
|
1240
|
+
if (part === "#" || part === "components") {
|
|
1241
|
+
continue;
|
|
1242
|
+
}
|
|
1243
|
+
current = current[part];
|
|
1244
|
+
if (!current) {
|
|
1245
|
+
return null;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
return current;
|
|
1249
|
+
}
|
|
1250
|
+
static addComponent(componentName, usedComponentsSet, components) {
|
|
1251
|
+
if (usedComponentsSet.has(componentName)) {
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
usedComponentsSet.add(componentName);
|
|
1255
|
+
const component = this.getComponent(componentName, components);
|
|
1256
|
+
if (component) {
|
|
1257
|
+
const componentString = JSON.stringify(component);
|
|
1258
|
+
const componentReferences = SpecOptimizer.getComponentReferences(componentString);
|
|
1259
|
+
for (const reference of componentReferences) {
|
|
1260
|
+
this.addComponent(reference, usedComponentsSet, components);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
SpecOptimizer.defaultOptions = {
|
|
1266
|
+
removeUnusedComponents: true,
|
|
1267
|
+
removeUnusedTags: true,
|
|
1268
|
+
removeUserDefinedRootProperty: true,
|
|
1269
|
+
removeUnusedSecuritySchemas: true,
|
|
1270
|
+
};
|
|
1271
|
+
|
|
1108
1272
|
// Copyright (c) Microsoft Corporation.
|
|
1109
1273
|
class SpecFilter {
|
|
1110
1274
|
static specFilter(filter, unResolveSpec, resolvedSpec, options) {
|
|
@@ -1138,7 +1302,7 @@ class SpecFilter {
|
|
|
1138
1302
|
}
|
|
1139
1303
|
}
|
|
1140
1304
|
newSpec.paths = newPaths;
|
|
1141
|
-
return newSpec;
|
|
1305
|
+
return SpecOptimizer.optimize(newSpec);
|
|
1142
1306
|
}
|
|
1143
1307
|
catch (err) {
|
|
1144
1308
|
throw new SpecParserError(err.toString(), ErrorType.FilterSpecFailed);
|
|
@@ -1261,7 +1425,7 @@ class AdaptiveCardGenerator {
|
|
|
1261
1425
|
{
|
|
1262
1426
|
type: "Image",
|
|
1263
1427
|
url: `\${${name}}`,
|
|
1264
|
-
$when: `\${${name} != null}`,
|
|
1428
|
+
$when: `\${${name} != null && ${name} != ''}`,
|
|
1265
1429
|
},
|
|
1266
1430
|
];
|
|
1267
1431
|
}
|
|
@@ -1270,7 +1434,7 @@ class AdaptiveCardGenerator {
|
|
|
1270
1434
|
{
|
|
1271
1435
|
type: "Image",
|
|
1272
1436
|
url: "${$data}",
|
|
1273
|
-
$when: "${$data != null}",
|
|
1437
|
+
$when: "${$data != null && $data != ''}",
|
|
1274
1438
|
},
|
|
1275
1439
|
];
|
|
1276
1440
|
}
|
|
@@ -1363,7 +1527,7 @@ function inferPreviewCardTemplate(card) {
|
|
|
1363
1527
|
result.image = {
|
|
1364
1528
|
url: `\${${inferredProperties.imageUrl}}`,
|
|
1365
1529
|
alt: `\${if(${inferredProperties.imageUrl}, ${inferredProperties.imageUrl}, 'N/A')}`,
|
|
1366
|
-
$when: `\${${inferredProperties.imageUrl} != null}`,
|
|
1530
|
+
$when: `\${${inferredProperties.imageUrl} != null && ${inferredProperties.imageUrl} != ''}`,
|
|
1367
1531
|
};
|
|
1368
1532
|
}
|
|
1369
1533
|
return result;
|
|
@@ -1532,9 +1696,18 @@ class ManifestUpdater {
|
|
|
1532
1696
|
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
|
|
1533
1697
|
}
|
|
1534
1698
|
}
|
|
1699
|
+
let funcDescription = operationItem.description || operationItem.summary || "";
|
|
1700
|
+
if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
|
|
1701
|
+
warnings.push({
|
|
1702
|
+
type: WarningType.FuncDescriptionTooLong,
|
|
1703
|
+
content: Utils.format(ConstantString.FuncDescriptionTooLong, safeFunctionName, funcDescription.length.toString(), ConstantString.FunctionDescriptionMaxLens.toString()),
|
|
1704
|
+
data: safeFunctionName,
|
|
1705
|
+
});
|
|
1706
|
+
funcDescription = funcDescription.slice(0, ConstantString.FunctionDescriptionMaxLens);
|
|
1707
|
+
}
|
|
1535
1708
|
const funcObj = {
|
|
1536
1709
|
name: safeFunctionName,
|
|
1537
|
-
description:
|
|
1710
|
+
description: funcDescription,
|
|
1538
1711
|
};
|
|
1539
1712
|
if (options.allowResponseSemantics) {
|
|
1540
1713
|
try {
|
|
@@ -1975,7 +2148,7 @@ class SpecParser {
|
|
|
1975
2148
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
1976
2149
|
* @param pluginFilePath File path of the api plugin file to generate.
|
|
1977
2150
|
*/
|
|
1978
|
-
async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
2151
|
+
async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, existingPluginFilePath, signal) {
|
|
1979
2152
|
const result = {
|
|
1980
2153
|
allSuccess: true,
|
|
1981
2154
|
warnings: [],
|
|
@@ -1992,7 +2165,15 @@ class SpecParser {
|
|
|
1992
2165
|
const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authInfo);
|
|
1993
2166
|
result.warnings.push(...warnings);
|
|
1994
2167
|
await fs.outputJSON(manifestPath, updatedManifest, { spaces: 4 });
|
|
1995
|
-
|
|
2168
|
+
if (existingPluginFilePath) {
|
|
2169
|
+
const originPluginManifest = (await fs.readJSON(existingPluginFilePath));
|
|
2170
|
+
// TODO (kiota): refactor to avoid generate apiPlugin
|
|
2171
|
+
originPluginManifest.functions = apiPlugin.functions;
|
|
2172
|
+
await fs.outputJSON(pluginFilePath, originPluginManifest, { spaces: 4 });
|
|
2173
|
+
}
|
|
2174
|
+
else {
|
|
2175
|
+
await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
|
|
2176
|
+
}
|
|
1996
2177
|
}
|
|
1997
2178
|
catch (err) {
|
|
1998
2179
|
if (err instanceof SpecParserError) {
|