@microsoft/m365-spec-parser 0.2.1 → 0.2.2-alpha.089f82c02.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 +52 -4
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +106 -26
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +52 -4
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +106 -26
- 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 +6 -1
- package/dist/src/specParser.d.ts +1 -0
- package/dist/src/utils.d.ts +5 -5
- package/package.json +3 -3
package/dist/index.esm2017.mjs
CHANGED
|
@@ -17,10 +17,12 @@ var ErrorType;
|
|
|
17
17
|
ErrorType["RelativeServerUrlNotSupported"] = "relative-server-url-not-supported";
|
|
18
18
|
ErrorType["NoSupportedApi"] = "no-supported-api";
|
|
19
19
|
ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
|
|
20
|
+
ErrorType["AddedAPINotInOriginalSpec"] = "added-api-not-in-original-spec";
|
|
20
21
|
ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
|
|
21
22
|
ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
|
|
22
23
|
ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
|
|
23
24
|
ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
|
|
25
|
+
ErrorType["CircularReferenceNotSupported"] = "circular-reference-not-supported";
|
|
24
26
|
ErrorType["ListFailed"] = "list-failed";
|
|
25
27
|
ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
|
|
26
28
|
ErrorType["FilterSpecFailed"] = "filter-spec-failed";
|
|
@@ -257,7 +259,7 @@ class Utils {
|
|
|
257
259
|
static updateFirstLetter(str) {
|
|
258
260
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
259
261
|
}
|
|
260
|
-
static getResponseJson(operationObject) {
|
|
262
|
+
static getResponseJson(operationObject, allowMultipleMediaType = false) {
|
|
261
263
|
var _a, _b;
|
|
262
264
|
let json = {};
|
|
263
265
|
let multipleMediaType = false;
|
|
@@ -268,7 +270,9 @@ class Utils {
|
|
|
268
270
|
json = responseObject.content["application/json"];
|
|
269
271
|
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
270
272
|
multipleMediaType = true;
|
|
271
|
-
|
|
273
|
+
if (!allowMultipleMediaType) {
|
|
274
|
+
json = {};
|
|
275
|
+
}
|
|
272
276
|
}
|
|
273
277
|
else {
|
|
274
278
|
break;
|
|
@@ -536,6 +540,19 @@ class Utils {
|
|
|
536
540
|
|
|
537
541
|
// Copyright (c) Microsoft Corporation.
|
|
538
542
|
class Validator {
|
|
543
|
+
constructor() {
|
|
544
|
+
this.hasCircularReference = false;
|
|
545
|
+
}
|
|
546
|
+
checkCircularReference() {
|
|
547
|
+
try {
|
|
548
|
+
JSON.stringify(this.spec);
|
|
549
|
+
}
|
|
550
|
+
catch (e) {
|
|
551
|
+
if (e.message.includes("Converting circular structure to JSON")) {
|
|
552
|
+
this.hasCircularReference = true;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
539
556
|
listAPIs() {
|
|
540
557
|
var _a;
|
|
541
558
|
if (this.apiMap) {
|
|
@@ -631,6 +648,22 @@ class Validator {
|
|
|
631
648
|
}
|
|
632
649
|
return result;
|
|
633
650
|
}
|
|
651
|
+
validateCircularReference(method, path) {
|
|
652
|
+
const result = { isValid: true, reason: [] };
|
|
653
|
+
if (this.hasCircularReference) {
|
|
654
|
+
const operationObject = this.spec.paths[path][method];
|
|
655
|
+
try {
|
|
656
|
+
JSON.stringify(operationObject);
|
|
657
|
+
}
|
|
658
|
+
catch (e) {
|
|
659
|
+
if (e.message.includes("Converting circular structure to JSON")) {
|
|
660
|
+
result.isValid = false;
|
|
661
|
+
result.reason.push(ErrorType.CircularReferenceNotSupported);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return result;
|
|
666
|
+
}
|
|
634
667
|
validateResponse(method, path) {
|
|
635
668
|
const result = { isValid: true, reason: [] };
|
|
636
669
|
const operationObject = this.spec.paths[path][method];
|
|
@@ -819,6 +852,7 @@ class CopilotValidator extends Validator {
|
|
|
819
852
|
this.projectType = ProjectType.Copilot;
|
|
820
853
|
this.options = options;
|
|
821
854
|
this.spec = spec;
|
|
855
|
+
this.checkCircularReference();
|
|
822
856
|
}
|
|
823
857
|
validateSpec() {
|
|
824
858
|
const result = { errors: [], warnings: [] };
|
|
@@ -844,6 +878,10 @@ class CopilotValidator extends Validator {
|
|
|
844
878
|
if (!methodAndPathResult.isValid) {
|
|
845
879
|
return methodAndPathResult;
|
|
846
880
|
}
|
|
881
|
+
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
882
|
+
if (!circularReferenceResult.isValid) {
|
|
883
|
+
return circularReferenceResult;
|
|
884
|
+
}
|
|
847
885
|
const operationObject = this.spec.paths[path][method];
|
|
848
886
|
// validate auth
|
|
849
887
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -887,6 +925,7 @@ class SMEValidator extends Validator {
|
|
|
887
925
|
this.projectType = ProjectType.SME;
|
|
888
926
|
this.options = options;
|
|
889
927
|
this.spec = spec;
|
|
928
|
+
this.checkCircularReference();
|
|
890
929
|
}
|
|
891
930
|
validateSpec() {
|
|
892
931
|
const result = { errors: [], warnings: [] };
|
|
@@ -914,6 +953,10 @@ class SMEValidator extends Validator {
|
|
|
914
953
|
if (!methodAndPathResult.isValid) {
|
|
915
954
|
return methodAndPathResult;
|
|
916
955
|
}
|
|
956
|
+
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
957
|
+
if (!circularReferenceResult.isValid) {
|
|
958
|
+
return circularReferenceResult;
|
|
959
|
+
}
|
|
917
960
|
const operationObject = this.spec.paths[path][method];
|
|
918
961
|
// validate auth
|
|
919
962
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -984,6 +1027,7 @@ class TeamsAIValidator extends Validator {
|
|
|
984
1027
|
this.projectType = ProjectType.TeamsAi;
|
|
985
1028
|
this.options = options;
|
|
986
1029
|
this.spec = spec;
|
|
1030
|
+
this.checkCircularReference();
|
|
987
1031
|
}
|
|
988
1032
|
validateSpec() {
|
|
989
1033
|
const result = { errors: [], warnings: [] };
|
|
@@ -1003,6 +1047,10 @@ class TeamsAIValidator extends Validator {
|
|
|
1003
1047
|
if (!methodAndPathResult.isValid) {
|
|
1004
1048
|
return methodAndPathResult;
|
|
1005
1049
|
}
|
|
1050
|
+
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
1051
|
+
if (!circularReferenceResult.isValid) {
|
|
1052
|
+
return circularReferenceResult;
|
|
1053
|
+
}
|
|
1006
1054
|
const operationObject = this.spec.paths[path][method];
|
|
1007
1055
|
// validate operationId
|
|
1008
1056
|
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
@@ -1078,9 +1126,9 @@ class SpecFilter {
|
|
|
1078
1126
|
|
|
1079
1127
|
// Copyright (c) Microsoft Corporation.
|
|
1080
1128
|
class AdaptiveCardGenerator {
|
|
1081
|
-
static generateAdaptiveCard(operationItem) {
|
|
1129
|
+
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
|
|
1082
1130
|
try {
|
|
1083
|
-
const { json } = Utils.getResponseJson(operationItem);
|
|
1131
|
+
const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
|
|
1084
1132
|
let cardBody = [];
|
|
1085
1133
|
let schema = json.schema;
|
|
1086
1134
|
let jsonPath = "$";
|
|
@@ -1596,7 +1644,6 @@ class ManifestUpdater {
|
|
|
1596
1644
|
const auth = authInfo.authScheme;
|
|
1597
1645
|
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
|
|
1598
1646
|
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1599
|
-
const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
|
|
1600
1647
|
composeExtension.authorization = {
|
|
1601
1648
|
authType: "apiSecretServiceAuth",
|
|
1602
1649
|
apiSecretServiceAuthConfiguration: {
|
|
@@ -1605,16 +1652,13 @@ class ManifestUpdater {
|
|
|
1605
1652
|
};
|
|
1606
1653
|
}
|
|
1607
1654
|
else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
|
|
1655
|
+
// TODO: below schema is coming from design doc, may need to update when shcema is finalized
|
|
1608
1656
|
composeExtension.authorization = {
|
|
1609
1657
|
authType: "oAuth2.0",
|
|
1610
1658
|
oAuthConfiguration: {
|
|
1611
1659
|
oauthConfigurationId: `\${{${safeRegistrationIdName}}}`,
|
|
1612
1660
|
},
|
|
1613
1661
|
};
|
|
1614
|
-
updatedPart.webApplicationInfo = {
|
|
1615
|
-
id: "${{AAD_APP_CLIENT_ID}}",
|
|
1616
|
-
resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
|
|
1617
|
-
};
|
|
1618
1662
|
}
|
|
1619
1663
|
}
|
|
1620
1664
|
updatedPart.composeExtensions = [composeExtension];
|
|
@@ -1650,12 +1694,17 @@ class ManifestUpdater {
|
|
|
1650
1694
|
command.parameters = command.parameters.filter((param) => param.isRequired);
|
|
1651
1695
|
}
|
|
1652
1696
|
else if (command.parameters && command.parameters.length > 0) {
|
|
1653
|
-
command.parameters
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1697
|
+
if (command.parameters.length > 1) {
|
|
1698
|
+
command.parameters = [command.parameters[0]];
|
|
1699
|
+
warnings.push({
|
|
1700
|
+
type: WarningType.OperationOnlyContainsOptionalParam,
|
|
1701
|
+
content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
|
|
1702
|
+
data: {
|
|
1703
|
+
commandId: command.id,
|
|
1704
|
+
parameterName: command.parameters[0].name,
|
|
1705
|
+
},
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1659
1708
|
}
|
|
1660
1709
|
if (adaptiveCardFolder) {
|
|
1661
1710
|
const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
|
|
@@ -1731,7 +1780,13 @@ class SpecParser {
|
|
|
1731
1780
|
try {
|
|
1732
1781
|
try {
|
|
1733
1782
|
await this.loadSpec();
|
|
1734
|
-
|
|
1783
|
+
if (!this.parser.$refs.circular) {
|
|
1784
|
+
await this.parser.validate(this.spec);
|
|
1785
|
+
}
|
|
1786
|
+
else {
|
|
1787
|
+
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
1788
|
+
await this.parser.validate(clonedUnResolveSpec);
|
|
1789
|
+
}
|
|
1735
1790
|
}
|
|
1736
1791
|
catch (e) {
|
|
1737
1792
|
return {
|
|
@@ -1819,19 +1874,36 @@ class SpecParser {
|
|
|
1819
1874
|
isValid: isValid,
|
|
1820
1875
|
reason: reason,
|
|
1821
1876
|
};
|
|
1822
|
-
|
|
1877
|
+
// Try best to parse server url and auth type
|
|
1878
|
+
try {
|
|
1823
1879
|
const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
|
|
1824
1880
|
if (serverObj) {
|
|
1825
|
-
apiResult.server =
|
|
1881
|
+
apiResult.server = serverObj.url;
|
|
1826
1882
|
}
|
|
1883
|
+
}
|
|
1884
|
+
catch (err) {
|
|
1885
|
+
// ignore
|
|
1886
|
+
}
|
|
1887
|
+
try {
|
|
1827
1888
|
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1889
|
+
if (authArray.length !== 0) {
|
|
1890
|
+
for (const auths of authArray) {
|
|
1891
|
+
if (auths.length === 1) {
|
|
1892
|
+
apiResult.auth = auths[0];
|
|
1893
|
+
break;
|
|
1894
|
+
}
|
|
1895
|
+
else {
|
|
1896
|
+
apiResult.auth = {
|
|
1897
|
+
authScheme: { type: "multipleAuth" },
|
|
1898
|
+
name: auths.map((auth) => auth.name).join(", "),
|
|
1899
|
+
};
|
|
1900
|
+
}
|
|
1832
1901
|
}
|
|
1833
1902
|
}
|
|
1834
1903
|
}
|
|
1904
|
+
catch (err) {
|
|
1905
|
+
// ignore
|
|
1906
|
+
}
|
|
1835
1907
|
result.APIs.push(apiResult);
|
|
1836
1908
|
}
|
|
1837
1909
|
result.allAPICount = result.APIs.length;
|
|
@@ -1862,7 +1934,8 @@ class SpecParser {
|
|
|
1862
1934
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
1863
1935
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
1864
1936
|
}
|
|
1865
|
-
const
|
|
1937
|
+
const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
|
|
1938
|
+
const newSpec = (await this.parser.dereference(clonedUnResolveSpec));
|
|
1866
1939
|
return [newUnResolvedSpec, newSpec];
|
|
1867
1940
|
}
|
|
1868
1941
|
catch (err) {
|
|
@@ -1935,10 +2008,11 @@ class SpecParser {
|
|
|
1935
2008
|
const operation = newSpec.paths[url][method];
|
|
1936
2009
|
try {
|
|
1937
2010
|
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
1938
|
-
const
|
|
2011
|
+
const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2012
|
+
const fileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
|
|
1939
2013
|
const wrappedCard = wrapAdaptiveCard(card, jsonPath);
|
|
1940
2014
|
await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
|
|
1941
|
-
const dataFileName = path.join(adaptiveCardFolder, `${
|
|
2015
|
+
const dataFileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
|
|
1942
2016
|
await fs.outputJSON(dataFileName, {}, { spaces: 2 });
|
|
1943
2017
|
}
|
|
1944
2018
|
catch (err) {
|
|
@@ -1970,7 +2044,8 @@ class SpecParser {
|
|
|
1970
2044
|
}
|
|
1971
2045
|
async loadSpec() {
|
|
1972
2046
|
if (!this.spec) {
|
|
1973
|
-
|
|
2047
|
+
const spec = (await this.parser.parse(this.pathOrSpec));
|
|
2048
|
+
this.unResolveSpec = this.resolveEnvForSpec(spec);
|
|
1974
2049
|
// Convert swagger 2.0 to openapi 3.0
|
|
1975
2050
|
if (!this.unResolveSpec.openapi && this.unResolveSpec.swagger === "2.0") {
|
|
1976
2051
|
const specObj = await converter.convert(this.unResolveSpec, {});
|
|
@@ -2004,6 +2079,11 @@ class SpecParser {
|
|
|
2004
2079
|
}
|
|
2005
2080
|
await fs.outputFile(outputSpecPath, resultStr);
|
|
2006
2081
|
}
|
|
2082
|
+
resolveEnvForSpec(spec) {
|
|
2083
|
+
const specString = JSON.stringify(spec);
|
|
2084
|
+
const specResolved = Utils.resolveEnv(specString);
|
|
2085
|
+
return JSON.parse(specResolved);
|
|
2086
|
+
}
|
|
2007
2087
|
}
|
|
2008
2088
|
|
|
2009
2089
|
export { AdaptiveCardGenerator, ConstantString, ErrorType, ProjectType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|