@microsoft/m365-spec-parser 0.2.1 → 0.2.2-alpha.3031916b6.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.
@@ -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
- json = {};
315
+ if (!allowMultipleMediaType) {
316
+ json = {};
317
+ }
314
318
  }
315
319
  else {
316
320
  break;
@@ -578,6 +582,19 @@ class Utils {
578
582
 
579
583
  // Copyright (c) Microsoft Corporation.
580
584
  class Validator {
585
+ constructor() {
586
+ this.hasCircularReference = false;
587
+ }
588
+ checkCircularReference() {
589
+ try {
590
+ JSON.stringify(this.spec);
591
+ }
592
+ catch (e) {
593
+ if (e.message.includes("Converting circular structure to JSON")) {
594
+ this.hasCircularReference = true;
595
+ }
596
+ }
597
+ }
581
598
  listAPIs() {
582
599
  var _a;
583
600
  if (this.apiMap) {
@@ -673,6 +690,22 @@ class Validator {
673
690
  }
674
691
  return result;
675
692
  }
693
+ validateCircularReference(method, path) {
694
+ const result = { isValid: true, reason: [] };
695
+ if (this.hasCircularReference) {
696
+ const operationObject = this.spec.paths[path][method];
697
+ try {
698
+ JSON.stringify(operationObject);
699
+ }
700
+ catch (e) {
701
+ if (e.message.includes("Converting circular structure to JSON")) {
702
+ result.isValid = false;
703
+ result.reason.push(exports.ErrorType.CircularReferenceNotSupported);
704
+ }
705
+ }
706
+ }
707
+ return result;
708
+ }
676
709
  validateResponse(method, path) {
677
710
  const result = { isValid: true, reason: [] };
678
711
  const operationObject = this.spec.paths[path][method];
@@ -861,6 +894,7 @@ class CopilotValidator extends Validator {
861
894
  this.projectType = exports.ProjectType.Copilot;
862
895
  this.options = options;
863
896
  this.spec = spec;
897
+ this.checkCircularReference();
864
898
  }
865
899
  validateSpec() {
866
900
  const result = { errors: [], warnings: [] };
@@ -886,6 +920,10 @@ class CopilotValidator extends Validator {
886
920
  if (!methodAndPathResult.isValid) {
887
921
  return methodAndPathResult;
888
922
  }
923
+ const circularReferenceResult = this.validateCircularReference(method, path);
924
+ if (!circularReferenceResult.isValid) {
925
+ return circularReferenceResult;
926
+ }
889
927
  const operationObject = this.spec.paths[path][method];
890
928
  // validate auth
891
929
  const authCheckResult = this.validateAuth(method, path);
@@ -929,6 +967,7 @@ class SMEValidator extends Validator {
929
967
  this.projectType = exports.ProjectType.SME;
930
968
  this.options = options;
931
969
  this.spec = spec;
970
+ this.checkCircularReference();
932
971
  }
933
972
  validateSpec() {
934
973
  const result = { errors: [], warnings: [] };
@@ -956,6 +995,10 @@ class SMEValidator extends Validator {
956
995
  if (!methodAndPathResult.isValid) {
957
996
  return methodAndPathResult;
958
997
  }
998
+ const circularReferenceResult = this.validateCircularReference(method, path);
999
+ if (!circularReferenceResult.isValid) {
1000
+ return circularReferenceResult;
1001
+ }
959
1002
  const operationObject = this.spec.paths[path][method];
960
1003
  // validate auth
961
1004
  const authCheckResult = this.validateAuth(method, path);
@@ -1026,6 +1069,7 @@ class TeamsAIValidator extends Validator {
1026
1069
  this.projectType = exports.ProjectType.TeamsAi;
1027
1070
  this.options = options;
1028
1071
  this.spec = spec;
1072
+ this.checkCircularReference();
1029
1073
  }
1030
1074
  validateSpec() {
1031
1075
  const result = { errors: [], warnings: [] };
@@ -1045,6 +1089,10 @@ class TeamsAIValidator extends Validator {
1045
1089
  if (!methodAndPathResult.isValid) {
1046
1090
  return methodAndPathResult;
1047
1091
  }
1092
+ const circularReferenceResult = this.validateCircularReference(method, path);
1093
+ if (!circularReferenceResult.isValid) {
1094
+ return circularReferenceResult;
1095
+ }
1048
1096
  const operationObject = this.spec.paths[path][method];
1049
1097
  // validate operationId
1050
1098
  if (!this.options.allowMissingId && !operationObject.operationId) {
@@ -1120,9 +1168,9 @@ class SpecFilter {
1120
1168
 
1121
1169
  // Copyright (c) Microsoft Corporation.
1122
1170
  class AdaptiveCardGenerator {
1123
- static generateAdaptiveCard(operationItem) {
1171
+ static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
1124
1172
  try {
1125
- const { json } = Utils.getResponseJson(operationItem);
1173
+ const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
1126
1174
  let cardBody = [];
1127
1175
  let schema = json.schema;
1128
1176
  let jsonPath = "$";
@@ -1643,7 +1691,6 @@ class ManifestUpdater {
1643
1691
  const auth = authInfo.authScheme;
1644
1692
  const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1645
1693
  if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1646
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1647
1694
  composeExtension.authorization = {
1648
1695
  authType: "apiSecretServiceAuth",
1649
1696
  apiSecretServiceAuthConfiguration: {
@@ -1652,16 +1699,13 @@ class ManifestUpdater {
1652
1699
  };
1653
1700
  }
1654
1701
  else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
1702
+ // TODO: below schema is coming from design doc, may need to update when shcema is finalized
1655
1703
  composeExtension.authorization = {
1656
1704
  authType: "oAuth2.0",
1657
1705
  oAuthConfiguration: {
1658
1706
  oauthConfigurationId: `\${{${safeRegistrationIdName}}}`,
1659
1707
  },
1660
1708
  };
1661
- updatedPart.webApplicationInfo = {
1662
- id: "${{AAD_APP_CLIENT_ID}}",
1663
- resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
1664
- };
1665
1709
  }
1666
1710
  }
1667
1711
  updatedPart.composeExtensions = [composeExtension];
@@ -1699,12 +1743,17 @@ class ManifestUpdater {
1699
1743
  command.parameters = command.parameters.filter((param) => param.isRequired);
1700
1744
  }
1701
1745
  else if (command.parameters && command.parameters.length > 0) {
1702
- command.parameters = [command.parameters[0]];
1703
- warnings.push({
1704
- type: exports.WarningType.OperationOnlyContainsOptionalParam,
1705
- content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
1706
- data: command.id,
1707
- });
1746
+ if (command.parameters.length > 1) {
1747
+ command.parameters = [command.parameters[0]];
1748
+ warnings.push({
1749
+ type: exports.WarningType.OperationOnlyContainsOptionalParam,
1750
+ content: Utils.format(ConstantString.OperationOnlyContainsOptionalParam, command.id),
1751
+ data: {
1752
+ commandId: command.id,
1753
+ parameterName: command.parameters[0].name,
1754
+ },
1755
+ });
1756
+ }
1708
1757
  }
1709
1758
  if (adaptiveCardFolder) {
1710
1759
  const adaptiveCardPath = path__default['default'].join(adaptiveCardFolder, command.id + ".json");
@@ -1782,7 +1831,13 @@ class SpecParser {
1782
1831
  try {
1783
1832
  try {
1784
1833
  yield this.loadSpec();
1785
- yield this.parser.validate(this.spec);
1834
+ if (!this.parser.$refs.circular) {
1835
+ yield this.parser.validate(this.spec);
1836
+ }
1837
+ else {
1838
+ const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
1839
+ yield this.parser.validate(clonedUnResolveSpec);
1840
+ }
1786
1841
  }
1787
1842
  catch (e) {
1788
1843
  return {
@@ -1874,19 +1929,36 @@ class SpecParser {
1874
1929
  isValid: isValid,
1875
1930
  reason: reason,
1876
1931
  };
1877
- if (isValid) {
1932
+ // Try best to parse server url and auth type
1933
+ try {
1878
1934
  const serverObj = Utils.getServerObject(spec, method.toLocaleLowerCase(), path);
1879
1935
  if (serverObj) {
1880
- apiResult.server = Utils.resolveEnv(serverObj.url);
1936
+ apiResult.server = serverObj.url;
1881
1937
  }
1938
+ }
1939
+ catch (err) {
1940
+ // ignore
1941
+ }
1942
+ try {
1882
1943
  const authArray = Utils.getAuthArray(operation.security, spec);
1883
- for (const auths of authArray) {
1884
- if (auths.length === 1) {
1885
- apiResult.auth = auths[0];
1886
- break;
1944
+ if (authArray.length !== 0) {
1945
+ for (const auths of authArray) {
1946
+ if (auths.length === 1) {
1947
+ apiResult.auth = auths[0];
1948
+ break;
1949
+ }
1950
+ else {
1951
+ apiResult.auth = {
1952
+ authScheme: { type: "multipleAuth" },
1953
+ name: auths.map((auth) => auth.name).join(", "),
1954
+ };
1955
+ }
1887
1956
  }
1888
1957
  }
1889
1958
  }
1959
+ catch (err) {
1960
+ // ignore
1961
+ }
1890
1962
  result.APIs.push(apiResult);
1891
1963
  }
1892
1964
  result.allAPICount = result.APIs.length;
@@ -1919,7 +1991,8 @@ class SpecParser {
1919
1991
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1920
1992
  throw new SpecParserError(ConstantString.CancelledMessage, exports.ErrorType.Cancelled);
1921
1993
  }
1922
- const newSpec = (yield this.parser.dereference(newUnResolvedSpec));
1994
+ const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
1995
+ const newSpec = (yield this.parser.dereference(clonedUnResolveSpec));
1923
1996
  return [newUnResolvedSpec, newSpec];
1924
1997
  }
1925
1998
  catch (err) {
@@ -1996,10 +2069,11 @@ class SpecParser {
1996
2069
  const operation = newSpec.paths[url][method];
1997
2070
  try {
1998
2071
  const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
1999
- const fileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.json`);
2072
+ const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
2073
+ const fileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
2000
2074
  const wrappedCard = wrapAdaptiveCard(card, jsonPath);
2001
2075
  yield fs__default['default'].outputJSON(fileName, wrappedCard, { spaces: 2 });
2002
- const dataFileName = path__default['default'].join(adaptiveCardFolder, `${operation.operationId}.data.json`);
2076
+ const dataFileName = path__default['default'].join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
2003
2077
  yield fs__default['default'].outputJSON(dataFileName, {}, { spaces: 2 });
2004
2078
  }
2005
2079
  catch (err) {
@@ -2033,7 +2107,8 @@ class SpecParser {
2033
2107
  loadSpec() {
2034
2108
  return __awaiter(this, void 0, void 0, function* () {
2035
2109
  if (!this.spec) {
2036
- this.unResolveSpec = (yield this.parser.parse(this.pathOrSpec));
2110
+ const spec = (yield this.parser.parse(this.pathOrSpec));
2111
+ this.unResolveSpec = this.resolveEnvForSpec(spec);
2037
2112
  // Convert swagger 2.0 to openapi 3.0
2038
2113
  if (!this.unResolveSpec.openapi && this.unResolveSpec.swagger === "2.0") {
2039
2114
  const specObj = yield converter__default['default'].convert(this.unResolveSpec, {});
@@ -2070,6 +2145,11 @@ class SpecParser {
2070
2145
  yield fs__default['default'].outputFile(outputSpecPath, resultStr);
2071
2146
  });
2072
2147
  }
2148
+ resolveEnvForSpec(spec) {
2149
+ const specString = JSON.stringify(spec);
2150
+ const specResolved = Utils.resolveEnv(specString);
2151
+ return JSON.parse(specResolved);
2152
+ }
2073
2153
  }
2074
2154
 
2075
2155
  exports.AdaptiveCardGenerator = AdaptiveCardGenerator;