@microsoft/m365-spec-parser 0.2.1 → 0.2.2-alpha.0921562c9.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 +74 -4
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +132 -29
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +74 -4
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +132 -29
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/adaptiveCardGenerator.d.ts +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/interfaces.d.ts +9 -3
- package/dist/src/specParser.d.ts +1 -0
- package/dist/src/utils.d.ts +6 -5
- package/package.json +3 -3
package/dist/index.node.cjs.js
CHANGED
|
@@ -59,10 +59,12 @@ exports.ErrorType = void 0;
|
|
|
59
59
|
ErrorType["RelativeServerUrlNotSupported"] = "relative-server-url-not-supported";
|
|
60
60
|
ErrorType["NoSupportedApi"] = "no-supported-api";
|
|
61
61
|
ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
|
|
62
|
+
ErrorType["AddedAPINotInOriginalSpec"] = "added-api-not-in-original-spec";
|
|
62
63
|
ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
|
|
63
64
|
ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
|
|
64
65
|
ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
|
|
65
66
|
ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
|
|
67
|
+
ErrorType["CircularReferenceNotSupported"] = "circular-reference-not-supported";
|
|
66
68
|
ErrorType["ListFailed"] = "list-failed";
|
|
67
69
|
ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
|
|
68
70
|
ErrorType["FilterSpecFailed"] = "filter-spec-failed";
|
|
@@ -299,7 +301,7 @@ class Utils {
|
|
|
299
301
|
static updateFirstLetter(str) {
|
|
300
302
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
301
303
|
}
|
|
302
|
-
static getResponseJson(operationObject) {
|
|
304
|
+
static getResponseJson(operationObject, allowMultipleMediaType = false) {
|
|
303
305
|
var _a, _b;
|
|
304
306
|
let json = {};
|
|
305
307
|
let multipleMediaType = false;
|
|
@@ -310,7 +312,9 @@ class Utils {
|
|
|
310
312
|
json = responseObject.content["application/json"];
|
|
311
313
|
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
312
314
|
multipleMediaType = true;
|
|
313
|
-
|
|
315
|
+
if (!allowMultipleMediaType) {
|
|
316
|
+
json = {};
|
|
317
|
+
}
|
|
314
318
|
}
|
|
315
319
|
else {
|
|
316
320
|
break;
|
|
@@ -574,10 +578,45 @@ class Utils {
|
|
|
574
578
|
const serverUrl = operationServer || methodServer || rootServer;
|
|
575
579
|
return serverUrl;
|
|
576
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
|
+
}
|
|
577
603
|
}
|
|
578
604
|
|
|
579
605
|
// Copyright (c) Microsoft Corporation.
|
|
580
606
|
class Validator {
|
|
607
|
+
constructor() {
|
|
608
|
+
this.hasCircularReference = false;
|
|
609
|
+
}
|
|
610
|
+
checkCircularReference() {
|
|
611
|
+
try {
|
|
612
|
+
JSON.stringify(this.spec);
|
|
613
|
+
}
|
|
614
|
+
catch (e) {
|
|
615
|
+
if (e.message.includes("Converting circular structure to JSON")) {
|
|
616
|
+
this.hasCircularReference = true;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
581
620
|
listAPIs() {
|
|
582
621
|
var _a;
|
|
583
622
|
if (this.apiMap) {
|
|
@@ -673,6 +712,22 @@ class Validator {
|
|
|
673
712
|
}
|
|
674
713
|
return result;
|
|
675
714
|
}
|
|
715
|
+
validateCircularReference(method, path) {
|
|
716
|
+
const result = { isValid: true, reason: [] };
|
|
717
|
+
if (this.hasCircularReference) {
|
|
718
|
+
const operationObject = this.spec.paths[path][method];
|
|
719
|
+
try {
|
|
720
|
+
JSON.stringify(operationObject);
|
|
721
|
+
}
|
|
722
|
+
catch (e) {
|
|
723
|
+
if (e.message.includes("Converting circular structure to JSON")) {
|
|
724
|
+
result.isValid = false;
|
|
725
|
+
result.reason.push(exports.ErrorType.CircularReferenceNotSupported);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return result;
|
|
730
|
+
}
|
|
676
731
|
validateResponse(method, path) {
|
|
677
732
|
const result = { isValid: true, reason: [] };
|
|
678
733
|
const operationObject = this.spec.paths[path][method];
|
|
@@ -861,6 +916,7 @@ class CopilotValidator extends Validator {
|
|
|
861
916
|
this.projectType = exports.ProjectType.Copilot;
|
|
862
917
|
this.options = options;
|
|
863
918
|
this.spec = spec;
|
|
919
|
+
this.checkCircularReference();
|
|
864
920
|
}
|
|
865
921
|
validateSpec() {
|
|
866
922
|
const result = { errors: [], warnings: [] };
|
|
@@ -886,6 +942,10 @@ class CopilotValidator extends Validator {
|
|
|
886
942
|
if (!methodAndPathResult.isValid) {
|
|
887
943
|
return methodAndPathResult;
|
|
888
944
|
}
|
|
945
|
+
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
946
|
+
if (!circularReferenceResult.isValid) {
|
|
947
|
+
return circularReferenceResult;
|
|
948
|
+
}
|
|
889
949
|
const operationObject = this.spec.paths[path][method];
|
|
890
950
|
// validate auth
|
|
891
951
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -929,6 +989,7 @@ class SMEValidator extends Validator {
|
|
|
929
989
|
this.projectType = exports.ProjectType.SME;
|
|
930
990
|
this.options = options;
|
|
931
991
|
this.spec = spec;
|
|
992
|
+
this.checkCircularReference();
|
|
932
993
|
}
|
|
933
994
|
validateSpec() {
|
|
934
995
|
const result = { errors: [], warnings: [] };
|
|
@@ -956,6 +1017,10 @@ class SMEValidator extends Validator {
|
|
|
956
1017
|
if (!methodAndPathResult.isValid) {
|
|
957
1018
|
return methodAndPathResult;
|
|
958
1019
|
}
|
|
1020
|
+
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
1021
|
+
if (!circularReferenceResult.isValid) {
|
|
1022
|
+
return circularReferenceResult;
|
|
1023
|
+
}
|
|
959
1024
|
const operationObject = this.spec.paths[path][method];
|
|
960
1025
|
// validate auth
|
|
961
1026
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -1026,6 +1091,7 @@ class TeamsAIValidator extends Validator {
|
|
|
1026
1091
|
this.projectType = exports.ProjectType.TeamsAi;
|
|
1027
1092
|
this.options = options;
|
|
1028
1093
|
this.spec = spec;
|
|
1094
|
+
this.checkCircularReference();
|
|
1029
1095
|
}
|
|
1030
1096
|
validateSpec() {
|
|
1031
1097
|
const result = { errors: [], warnings: [] };
|
|
@@ -1045,6 +1111,10 @@ class TeamsAIValidator extends Validator {
|
|
|
1045
1111
|
if (!methodAndPathResult.isValid) {
|
|
1046
1112
|
return methodAndPathResult;
|
|
1047
1113
|
}
|
|
1114
|
+
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
1115
|
+
if (!circularReferenceResult.isValid) {
|
|
1116
|
+
return circularReferenceResult;
|
|
1117
|
+
}
|
|
1048
1118
|
const operationObject = this.spec.paths[path][method];
|
|
1049
1119
|
// validate operationId
|
|
1050
1120
|
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
@@ -1120,9 +1190,9 @@ class SpecFilter {
|
|
|
1120
1190
|
|
|
1121
1191
|
// Copyright (c) Microsoft Corporation.
|
|
1122
1192
|
class AdaptiveCardGenerator {
|
|
1123
|
-
static generateAdaptiveCard(operationItem) {
|
|
1193
|
+
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
|
|
1124
1194
|
try {
|
|
1125
|
-
const { json } = Utils.getResponseJson(operationItem);
|
|
1195
|
+
const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
|
|
1126
1196
|
let cardBody = [];
|
|
1127
1197
|
let schema = json.schema;
|
|
1128
1198
|
let jsonPath = "$";
|
|
@@ -1480,6 +1550,7 @@ class ManifestUpdater {
|
|
|
1480
1550
|
const confirmationBodies = [];
|
|
1481
1551
|
if (operationItem) {
|
|
1482
1552
|
const operationId = operationItem.operationId;
|
|
1553
|
+
const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1483
1554
|
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
1484
1555
|
const summary = operationItem.summary;
|
|
1485
1556
|
const paramObject = operationItem.parameters;
|
|
@@ -1507,7 +1578,7 @@ class ManifestUpdater {
|
|
|
1507
1578
|
}
|
|
1508
1579
|
}
|
|
1509
1580
|
const funcObj = {
|
|
1510
|
-
name:
|
|
1581
|
+
name: safeFunctionName,
|
|
1511
1582
|
description: description,
|
|
1512
1583
|
};
|
|
1513
1584
|
if (options.allowResponseSemantics) {
|
|
@@ -1515,7 +1586,7 @@ class ManifestUpdater {
|
|
|
1515
1586
|
const { json } = Utils.getResponseJson(operationItem);
|
|
1516
1587
|
if (json.schema) {
|
|
1517
1588
|
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem);
|
|
1518
|
-
card.body = card.body
|
|
1589
|
+
card.body = Utils.limitACBodyProperties(card.body, 5);
|
|
1519
1590
|
const responseSemantic = wrapResponseSemantics(card, jsonPath);
|
|
1520
1591
|
funcObj.capabilities = {
|
|
1521
1592
|
response_semantics: responseSemantic,
|
|
@@ -1543,7 +1614,7 @@ class ManifestUpdater {
|
|
|
1543
1614
|
}
|
|
1544
1615
|
}
|
|
1545
1616
|
functions.push(funcObj);
|
|
1546
|
-
functionNames.push(
|
|
1617
|
+
functionNames.push(safeFunctionName);
|
|
1547
1618
|
const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
|
|
1548
1619
|
if (conversationStarterStr) {
|
|
1549
1620
|
conversationStarters.push(conversationStarterStr);
|
|
@@ -1643,7 +1714,6 @@ class ManifestUpdater {
|
|
|
1643
1714
|
const auth = authInfo.authScheme;
|
|
1644
1715
|
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
|
|
1645
1716
|
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1646
|
-
const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
|
|
1647
1717
|
composeExtension.authorization = {
|
|
1648
1718
|
authType: "apiSecretServiceAuth",
|
|
1649
1719
|
apiSecretServiceAuthConfiguration: {
|
|
@@ -1652,16 +1722,13 @@ class ManifestUpdater {
|
|
|
1652
1722
|
};
|
|
1653
1723
|
}
|
|
1654
1724
|
else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
|
|
1725
|
+
// TODO: below schema is coming from design doc, may need to update when shcema is finalized
|
|
1655
1726
|
composeExtension.authorization = {
|
|
1656
1727
|
authType: "oAuth2.0",
|
|
1657
1728
|
oAuthConfiguration: {
|
|
1658
1729
|
oauthConfigurationId: `\${{${safeRegistrationIdName}}}`,
|
|
1659
1730
|
},
|
|
1660
1731
|
};
|
|
1661
|
-
updatedPart.webApplicationInfo = {
|
|
1662
|
-
id: "${{AAD_APP_CLIENT_ID}}",
|
|
1663
|
-
resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
|
|
1664
|
-
};
|
|
1665
1732
|
}
|
|
1666
1733
|
}
|
|
1667
1734
|
updatedPart.composeExtensions = [composeExtension];
|
|
@@ -1699,12 +1766,17 @@ class ManifestUpdater {
|
|
|
1699
1766
|
command.parameters = command.parameters.filter((param) => param.isRequired);
|
|
1700
1767
|
}
|
|
1701
1768
|
else if (command.parameters && command.parameters.length > 0) {
|
|
1702
|
-
command.parameters
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1769
|
+
if (command.parameters.length > 1) {
|
|
1770
|
+
command.parameters = [command.parameters[0]];
|
|
1771
|
+
warnings.push({
|
|
1772
|
+
type: exports.WarningType.OperationOnlyContainsOptionalParam,
|
|
1773
|
+
content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
|
|
1774
|
+
data: {
|
|
1775
|
+
commandId: command.id,
|
|
1776
|
+
parameterName: command.parameters[0].name,
|
|
1777
|
+
},
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1708
1780
|
}
|
|
1709
1781
|
if (adaptiveCardFolder) {
|
|
1710
1782
|
const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
|
|
@@ -1782,7 +1854,13 @@ class SpecParser {
|
|
|
1782
1854
|
try {
|
|
1783
1855
|
try {
|
|
1784
1856
|
yield this.loadSpec();
|
|
1785
|
-
|
|
1857
|
+
if (!this.parser.$refs.circular) {
|
|
1858
|
+
yield this.parser.validate(this.spec);
|
|
1859
|
+
}
|
|
1860
|
+
else {
|
|
1861
|
+
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
1862
|
+
yield this.parser.validate(clonedUnResolveSpec);
|
|
1863
|
+
}
|
|
1786
1864
|
}
|
|
1787
1865
|
catch (e) {
|
|
1788
1866
|
return {
|
|
@@ -1874,19 +1952,36 @@ class SpecParser {
|
|
|
1874
1952
|
isValid: isValid,
|
|
1875
1953
|
reason: reason,
|
|
1876
1954
|
};
|
|
1877
|
-
|
|
1955
|
+
// Try best to parse server url and auth type
|
|
1956
|
+
try {
|
|
1878
1957
|
const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
|
|
1879
1958
|
if (serverObj) {
|
|
1880
|
-
apiResult.server =
|
|
1959
|
+
apiResult.server = serverObj.url;
|
|
1881
1960
|
}
|
|
1961
|
+
}
|
|
1962
|
+
catch (err) {
|
|
1963
|
+
// ignore
|
|
1964
|
+
}
|
|
1965
|
+
try {
|
|
1882
1966
|
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1967
|
+
if (authArray.length !== 0) {
|
|
1968
|
+
for (const auths of authArray) {
|
|
1969
|
+
if (auths.length === 1) {
|
|
1970
|
+
apiResult.auth = auths[0];
|
|
1971
|
+
break;
|
|
1972
|
+
}
|
|
1973
|
+
else {
|
|
1974
|
+
apiResult.auth = {
|
|
1975
|
+
authScheme: { type: "multipleAuth" },
|
|
1976
|
+
name: auths.map((auth) => auth.name).join(", "),
|
|
1977
|
+
};
|
|
1978
|
+
}
|
|
1887
1979
|
}
|
|
1888
1980
|
}
|
|
1889
1981
|
}
|
|
1982
|
+
catch (err) {
|
|
1983
|
+
// ignore
|
|
1984
|
+
}
|
|
1890
1985
|
result.APIs.push(apiResult);
|
|
1891
1986
|
}
|
|
1892
1987
|
result.allAPICount = result.APIs.length;
|
|
@@ -1919,7 +2014,8 @@ class SpecParser {
|
|
|
1919
2014
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1920
2015
|
throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
|
|
1921
2016
|
}
|
|
1922
|
-
const
|
|
2017
|
+
const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
|
|
2018
|
+
const newSpec = (yield this.parser.dereference(clonedUnResolveSpec));
|
|
1923
2019
|
return [newUnResolvedSpec, newSpec];
|
|
1924
2020
|
}
|
|
1925
2021
|
catch (err) {
|
|
@@ -1996,10 +2092,11 @@ class SpecParser {
|
|
|
1996
2092
|
const operation = newSpec.paths[url][method];
|
|
1997
2093
|
try {
|
|
1998
2094
|
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
1999
|
-
const
|
|
2095
|
+
const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2096
|
+
const fileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
|
|
2000
2097
|
const wrappedCard = wrapAdaptiveCard(card, jsonPath);
|
|
2001
2098
|
yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
|
|
2002
|
-
const dataFileName = path__default['default'].join(adaptiveCardFolder, `${
|
|
2099
|
+
const dataFileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
|
|
2003
2100
|
yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
|
|
2004
2101
|
}
|
|
2005
2102
|
catch (err) {
|
|
@@ -2033,7 +2130,8 @@ class SpecParser {
|
|
|
2033
2130
|
loadSpec() {
|
|
2034
2131
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2035
2132
|
if (!this.spec) {
|
|
2036
|
-
|
|
2133
|
+
const spec = (yield this.parser.parse(this.pathOrSpec));
|
|
2134
|
+
this.unResolveSpec = this.resolveEnvForSpec(spec);
|
|
2037
2135
|
// Convert swagger 2.0 to openapi 3.0
|
|
2038
2136
|
if (!this.unResolveSpec.openapi && this.unResolveSpec.swagger === "2.0") {
|
|
2039
2137
|
const specObj = yield converter__default['default'].convert(this.unResolveSpec, {});
|
|
@@ -2070,6 +2168,11 @@ class SpecParser {
|
|
|
2070
2168
|
yield fs__default['default'].outputFile(outputSpecPath, resultStr);
|
|
2071
2169
|
});
|
|
2072
2170
|
}
|
|
2171
|
+
resolveEnvForSpec(spec) {
|
|
2172
|
+
const specString = JSON.stringify(spec);
|
|
2173
|
+
const specResolved = Utils.resolveEnv(specString);
|
|
2174
|
+
return JSON.parse(specResolved);
|
|
2175
|
+
}
|
|
2073
2176
|
}
|
|
2074
2177
|
|
|
2075
2178
|
exports.AdaptiveCardGenerator = AdaptiveCardGenerator;
|