@microsoft/m365-spec-parser 0.2.3-alpha.786f6c493.0 → 0.2.3-alpha.8abc127ff.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.
@@ -41,8 +41,6 @@ var ErrorType;
41
41
  ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
42
42
  ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
43
43
  ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
44
- ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
45
- ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
46
44
  ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
47
45
  ErrorType["NoParameter"] = "no-parameter";
48
46
  ErrorType["NoAPIInfo"] = "no-api-info";
@@ -110,7 +108,7 @@ ConstantString.WrappedCardResponseLayout = "list";
110
108
  ConstantString.GetMethod = "get";
111
109
  ConstantString.PostMethod = "post";
112
110
  ConstantString.AdaptiveCardVersion = "1.5";
113
- ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
111
+ ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
114
112
  ConstantString.AdaptiveCardType = "AdaptiveCard";
115
113
  ConstantString.TextBlockType = "TextBlock";
116
114
  ConstantString.ImageType = "Image";
@@ -197,17 +195,6 @@ class SpecParserError extends Error {
197
195
 
198
196
  // Copyright (c) Microsoft Corporation.
199
197
  class Utils {
200
- static hasNestedObjectInSchema(schema) {
201
- if (this.isObjectSchema(schema)) {
202
- for (const property in schema.properties) {
203
- const nestedSchema = schema.properties[property];
204
- if (this.isObjectSchema(nestedSchema)) {
205
- return true;
206
- }
207
- }
208
- }
209
- return false;
210
- }
211
198
  static isObjectSchema(schema) {
212
199
  return schema.type === "object" || (!schema.type && !!schema.properties);
213
200
  }
@@ -277,27 +264,33 @@ class Utils {
277
264
  let multipleMediaType = false;
278
265
  for (const code of ConstantString.ResponseCodeFor20X) {
279
266
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
280
- if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
281
- for (const contentType of Object.keys(responseObject.content)) {
282
- // json media type can also be "application/json; charset=utf-8"
283
- if (contentType.indexOf("application/json") >= 0) {
284
- multipleMediaType = false;
285
- json = responseObject.content[contentType];
286
- if (Utils.containMultipleMediaTypes(responseObject)) {
287
- multipleMediaType = true;
288
- if (!allowMultipleMediaType) {
289
- json = {};
290
- }
291
- }
292
- else {
293
- return { json, multipleMediaType };
294
- }
295
- }
296
- }
267
+ if (!responseObject) {
268
+ continue;
269
+ }
270
+ multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
271
+ if (!allowMultipleMediaType && multipleMediaType) {
272
+ json = {};
273
+ continue;
274
+ }
275
+ const mediaObj = Utils.getJsonContentType(responseObject);
276
+ if (Object.keys(mediaObj).length > 0) {
277
+ json = mediaObj;
278
+ return { json, multipleMediaType };
297
279
  }
298
280
  }
299
281
  return { json, multipleMediaType };
300
282
  }
283
+ static getJsonContentType(responseObject) {
284
+ if (responseObject.content) {
285
+ for (const contentType of Object.keys(responseObject.content)) {
286
+ // json media type can also be "application/json; charset=utf-8"
287
+ if (contentType.indexOf("application/json") >= 0) {
288
+ return responseObject.content[contentType];
289
+ }
290
+ }
291
+ }
292
+ return {};
293
+ }
301
294
  static convertPathToCamelCase(path) {
302
295
  const pathSegments = path.split(/[./{]/);
303
296
  const camelCaseSegments = pathSegments.map((segment) => {
@@ -333,7 +326,7 @@ class Utils {
333
326
  }
334
327
  return newStr;
335
328
  }
336
- static checkServerUrl(servers) {
329
+ static checkServerUrl(servers, allowHttp = false) {
337
330
  const errors = [];
338
331
  let serverUrl;
339
332
  try {
@@ -356,8 +349,7 @@ class Utils {
356
349
  data: servers,
357
350
  });
358
351
  }
359
- else if (protocol !== "https:") {
360
- // Http server url is not supported
352
+ else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
361
353
  const protocolString = protocol.slice(0, -1);
362
354
  errors.push({
363
355
  type: ErrorType.UrlProtocolNotSupported,
@@ -373,10 +365,11 @@ class Utils {
373
365
  let hasTopLevelServers = false;
374
366
  let hasPathLevelServers = false;
375
367
  let hasOperationLevelServers = false;
368
+ const allowHttp = options.projectType === ProjectType.Copilot;
376
369
  if (spec.servers && spec.servers.length >= 1) {
377
370
  hasTopLevelServers = true;
378
371
  // for multiple server, we only use the first url
379
- const serverErrors = Utils.checkServerUrl(spec.servers);
372
+ const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
380
373
  errors.push(...serverErrors);
381
374
  }
382
375
  const paths = spec.paths;
@@ -384,7 +377,7 @@ class Utils {
384
377
  const methods = paths[path];
385
378
  if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
386
379
  hasPathLevelServers = true;
387
- const serverErrors = Utils.checkServerUrl(methods.servers);
380
+ const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
388
381
  errors.push(...serverErrors);
389
382
  }
390
383
  for (const method in methods) {
@@ -392,7 +385,7 @@ class Utils {
392
385
  if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
393
386
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
394
387
  hasOperationLevelServers = true;
395
- const serverErrors = Utils.checkServerUrl(operationObject.servers);
388
+ const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
396
389
  errors.push(...serverErrors);
397
390
  }
398
391
  }
@@ -705,8 +698,8 @@ class Validator {
705
698
  result.reason.push(ErrorType.NoServerInformation);
706
699
  }
707
700
  else {
708
- // server url should be absolute url with https protocol
709
- const serverValidateResult = Utils.checkServerUrl([serverObj]);
701
+ const allowHttp = this.projectType === ProjectType.Copilot;
702
+ const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
710
703
  result.reason.push(...serverValidateResult.map((item) => item.type));
711
704
  }
712
705
  return result;
@@ -754,11 +747,6 @@ class Validator {
754
747
  }
755
748
  const isRequiredWithoutDefault = isRequired && schema.default === undefined;
756
749
  const isCopilot = this.projectType === ProjectType.Copilot;
757
- if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
758
- paramResult.isValid = false;
759
- paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
760
- return paramResult;
761
- }
762
750
  if (schema.type === "string" ||
763
751
  schema.type === "integer" ||
764
752
  schema.type === "boolean" ||
@@ -806,11 +794,6 @@ class Validator {
806
794
  for (let i = 0; i < paramObject.length; i++) {
807
795
  const param = paramObject[i];
808
796
  const schema = param.schema;
809
- if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
810
- paramResult.isValid = false;
811
- paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
812
- continue;
813
- }
814
797
  const isRequiredWithoutDefault = param.required && schema.default === undefined;
815
798
  if (isCopilot) {
816
799
  if (isRequiredWithoutDefault) {
@@ -1285,15 +1268,152 @@ class SpecFilter {
1285
1268
  }
1286
1269
  }
1287
1270
 
1271
+ // Copyright (c) Microsoft Corporation.
1272
+ class JsonDataGenerator {
1273
+ static generate(schema) {
1274
+ return this.generateMockData(schema);
1275
+ }
1276
+ static generateMockData(schema) {
1277
+ if (this.visitedSchemas.has(schema)) {
1278
+ return null; // Prevent circular reference
1279
+ }
1280
+ this.visitedSchemas.add(schema);
1281
+ let result;
1282
+ if (schema.anyOf) {
1283
+ // Select the first schema in anyOf
1284
+ const selectedSchema = schema.anyOf[0];
1285
+ result = this.generateMockData(selectedSchema);
1286
+ }
1287
+ else if (schema.oneOf) {
1288
+ // Select the first schema in oneOf
1289
+ const selectedSchema = schema.oneOf[0];
1290
+ result = this.generateMockData(selectedSchema);
1291
+ }
1292
+ else if (schema.allOf) {
1293
+ // merge all schemas in allOf
1294
+ result = {};
1295
+ for (const subschema of schema.allOf) {
1296
+ const data = this.generateMockData(subschema);
1297
+ result = Object.assign(Object.assign({}, result), data);
1298
+ }
1299
+ }
1300
+ else {
1301
+ switch (schema.type) {
1302
+ case "string":
1303
+ if (schema.example !== undefined) {
1304
+ result = schema.example;
1305
+ }
1306
+ else if (schema.format) {
1307
+ switch (schema.format) {
1308
+ case "date-time":
1309
+ result = "2024-11-01T05:25:43.593Z";
1310
+ break;
1311
+ case "email":
1312
+ result = "example@example.com";
1313
+ break;
1314
+ case "uuid":
1315
+ result = "123e4567-e89b-12d3-a456-426614174000";
1316
+ break;
1317
+ case "ipv4":
1318
+ result = "192.168.0.1";
1319
+ break;
1320
+ case "ipv6":
1321
+ result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
1322
+ break;
1323
+ default:
1324
+ result = "example string";
1325
+ }
1326
+ }
1327
+ else {
1328
+ result = "example string";
1329
+ }
1330
+ break;
1331
+ case "number":
1332
+ if (schema.example !== undefined) {
1333
+ result = schema.example;
1334
+ }
1335
+ else if (schema.format) {
1336
+ switch (schema.format) {
1337
+ case "float":
1338
+ result = 3.14;
1339
+ break;
1340
+ case "double":
1341
+ result = 3.14159;
1342
+ break;
1343
+ default:
1344
+ result = 123;
1345
+ }
1346
+ }
1347
+ else {
1348
+ result = 123;
1349
+ }
1350
+ break;
1351
+ case "integer":
1352
+ if (schema.example !== undefined) {
1353
+ result = schema.example;
1354
+ }
1355
+ else if (schema.format) {
1356
+ switch (schema.format) {
1357
+ case "int32":
1358
+ result = 123456;
1359
+ break;
1360
+ case "int64":
1361
+ result = 123456789;
1362
+ break;
1363
+ default:
1364
+ result = 123;
1365
+ }
1366
+ }
1367
+ else {
1368
+ result = 123;
1369
+ }
1370
+ break;
1371
+ case "boolean":
1372
+ result = schema.example !== undefined ? schema.example : true;
1373
+ break;
1374
+ case "array":
1375
+ result = [this.generateMockData(schema.items)];
1376
+ break;
1377
+ case "object":
1378
+ result = {};
1379
+ if (schema.properties) {
1380
+ for (const key in schema.properties) {
1381
+ result[key] = this.generateMockData(schema.properties[key]);
1382
+ }
1383
+ }
1384
+ break;
1385
+ default:
1386
+ result = schema.example || null;
1387
+ }
1388
+ }
1389
+ this.visitedSchemas.delete(schema);
1390
+ return result;
1391
+ }
1392
+ }
1393
+ JsonDataGenerator.visitedSchemas = new Set();
1394
+
1288
1395
  // Copyright (c) Microsoft Corporation.
1289
1396
  class AdaptiveCardGenerator {
1290
1397
  static generateAdaptiveCard(operationItem, allowMultipleMediaType = false, maxElementCount = Number.MAX_SAFE_INTEGER) {
1291
1398
  try {
1292
1399
  const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
1293
1400
  let cardBody = [];
1401
+ let jsonData = {};
1402
+ const warnings = [];
1403
+ const operationId = operationItem.operationId;
1294
1404
  let schema = json.schema;
1295
1405
  let jsonPath = "$";
1296
1406
  if (schema && Object.keys(schema).length > 0) {
1407
+ try {
1408
+ jsonData = JsonDataGenerator.generate(schema);
1409
+ }
1410
+ catch (err) {
1411
+ warnings.push({
1412
+ type: WarningType.GenerateJsonDataFailed,
1413
+ content: Utils.format(ConstantString.GenerateJsonDataFailed, operationId, err.toString()),
1414
+ data: operationId,
1415
+ });
1416
+ }
1297
1417
  jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
1298
1418
  if (jsonPath !== "$") {
1299
1419
  schema = schema.properties[jsonPath];
@@ -1326,7 +1446,7 @@ class AdaptiveCardGenerator {
1326
1446
  version: ConstantString.AdaptiveCardVersion,
1327
1447
  body: cardBody,
1328
1448
  };
1329
- return [fullCard, jsonPath];
1449
+ return [fullCard, jsonPath, jsonData, warnings];
1330
1450
  }
1331
1451
  catch (err) {
1332
1452
  throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
@@ -1653,36 +1773,11 @@ class ManifestUpdater {
1653
1773
  for (const method in operations) {
1654
1774
  if (options.allowMethods.includes(method)) {
1655
1775
  const operationItem = operations[method];
1656
- const confirmationBodies = [];
1657
1776
  if (operationItem) {
1658
1777
  const operationId = operationItem.operationId;
1659
1778
  const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
1660
1779
  const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1661
1780
  const summary = operationItem.summary;
1662
- const paramObject = operationItem.parameters;
1663
- const requestBody = operationItem.requestBody;
1664
- if (paramObject) {
1665
- for (let i = 0; i < paramObject.length; i++) {
1666
- const param = paramObject[i];
1667
- const schema = param.schema;
1668
- ManifestUpdater.checkSchema(schema, method, pathUrl);
1669
- confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
1670
- }
1671
- }
1672
- if (requestBody) {
1673
- const requestJsonBody = requestBody.content["application/json"];
1674
- const requestBodySchema = requestJsonBody.schema;
1675
- if (Utils.isObjectSchema(requestBodySchema)) {
1676
- for (const property in requestBodySchema.properties) {
1677
- const schema = requestBodySchema.properties[property];
1678
- ManifestUpdater.checkSchema(schema, method, pathUrl);
1679
- confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
1680
- }
1681
- }
1682
- else {
1683
- throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
1684
- }
1685
- }
1686
1781
  let funcDescription = operationItem.description || operationItem.summary || "";
1687
1782
  if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
1688
1783
  warnings.push({
@@ -1716,14 +1811,39 @@ class ManifestUpdater {
1716
1811
  }
1717
1812
  }
1718
1813
  if (options.allowConfirmation && method !== ConstantString.GetMethod) {
1719
- if (!funcObj.capabilities) {
1720
- funcObj.capabilities = {};
1814
+ const paramObject = operationItem.parameters;
1815
+ const requestBody = operationItem.requestBody;
1816
+ const confirmationBodies = [];
1817
+ if (paramObject) {
1818
+ for (let i = 0; i < paramObject.length; i++) {
1819
+ const param = paramObject[i];
1820
+ const schema = param.schema;
1821
+ ManifestUpdater.checkSchema(schema, method, pathUrl);
1822
+ confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
1823
+ }
1824
+ }
1825
+ if (requestBody) {
1826
+ const requestJsonBody = Utils.getJsonContentType(requestBody);
1827
+ const requestBodySchema = requestJsonBody.schema;
1828
+ if (Utils.isObjectSchema(requestBodySchema)) {
1829
+ for (const property in requestBodySchema.properties) {
1830
+ const schema = requestBodySchema.properties[property];
1831
+ ManifestUpdater.checkSchema(schema, method, pathUrl);
1832
+ confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
1833
+ }
1834
+ }
1835
+ else {
1836
+ throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
1837
+ }
1721
1838
  }
1722
- funcObj.capabilities.confirmation = {
1723
- type: "AdaptiveCard",
1724
- title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
1725
- };
1726
1839
  if (confirmationBodies.length > 0) {
1840
+ if (!funcObj.capabilities) {
1841
+ funcObj.capabilities = {};
1842
+ }
1843
+ funcObj.capabilities.confirmation = {
1844
+ type: "AdaptiveCard",
1845
+ title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
1846
+ };
1727
1847
  funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
1728
1848
  }
1729
1849
  }
@@ -1933,130 +2053,6 @@ class ManifestUpdater {
1933
2053
  }
1934
2054
  }
1935
2055
 
1936
- // Copyright (c) Microsoft Corporation.
1937
- class JsonDataGenerator {
1938
- static generate(schema) {
1939
- return this.generateMockData(schema);
1940
- }
1941
- static generateMockData(schema) {
1942
- if (this.visitedSchemas.has(schema)) {
1943
- return null; // Prevent circular reference
1944
- }
1945
- this.visitedSchemas.add(schema);
1946
- let result;
1947
- if (schema.anyOf) {
1948
- // Select the first schema in anyOf
1949
- const selectedSchema = schema.anyOf[0];
1950
- result = this.generateMockData(selectedSchema);
1951
- }
1952
- else if (schema.oneOf) {
1953
- // Select the first schema in oneOf
1954
- const selectedSchema = schema.oneOf[0];
1955
- result = this.generateMockData(selectedSchema);
1956
- }
1957
- else if (schema.allOf) {
1958
- // merge all schemas in allOf
1959
- result = {};
1960
- for (const subschema of schema.allOf) {
1961
- const data = this.generateMockData(subschema);
1962
- result = Object.assign(Object.assign({}, result), data);
1963
- }
1964
- }
1965
- else {
1966
- switch (schema.type) {
1967
- case "string":
1968
- if (schema.example !== undefined) {
1969
- result = schema.example;
1970
- }
1971
- else if (schema.format) {
1972
- switch (schema.format) {
1973
- case "date-time":
1974
- result = "2024-11-01T05:25:43.593Z";
1975
- break;
1976
- case "email":
1977
- result = "example@example.com";
1978
- break;
1979
- case "uuid":
1980
- result = "123e4567-e89b-12d3-a456-426614174000";
1981
- break;
1982
- case "ipv4":
1983
- result = "192.168.0.1";
1984
- break;
1985
- case "ipv6":
1986
- result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
1987
- break;
1988
- default:
1989
- result = "example string";
1990
- }
1991
- }
1992
- else {
1993
- result = "example string";
1994
- }
1995
- break;
1996
- case "number":
1997
- if (schema.example !== undefined) {
1998
- result = schema.example;
1999
- }
2000
- else if (schema.format) {
2001
- switch (schema.format) {
2002
- case "float":
2003
- result = 3.14;
2004
- break;
2005
- case "double":
2006
- result = 3.14159;
2007
- break;
2008
- default:
2009
- result = 123;
2010
- }
2011
- }
2012
- else {
2013
- result = 123;
2014
- }
2015
- break;
2016
- case "integer":
2017
- if (schema.example !== undefined) {
2018
- result = schema.example;
2019
- }
2020
- else if (schema.format) {
2021
- switch (schema.format) {
2022
- case "int32":
2023
- result = 123456;
2024
- break;
2025
- case "int64":
2026
- result = 123456789;
2027
- break;
2028
- default:
2029
- result = 123;
2030
- }
2031
- }
2032
- else {
2033
- result = 123;
2034
- }
2035
- break;
2036
- case "boolean":
2037
- result = schema.example !== undefined ? schema.example : true;
2038
- break;
2039
- case "array":
2040
- result = [this.generateMockData(schema.items)];
2041
- break;
2042
- case "object":
2043
- result = {};
2044
- if (schema.properties) {
2045
- for (const key in schema.properties) {
2046
- result[key] = this.generateMockData(schema.properties[key]);
2047
- }
2048
- }
2049
- break;
2050
- default:
2051
- result = schema.example || null;
2052
- }
2053
- }
2054
- this.visitedSchemas.delete(schema);
2055
- return result;
2056
- }
2057
- }
2058
- JsonDataGenerator.visitedSchemas = new Set();
2059
-
2060
2056
  // Copyright (c) Microsoft Corporation.
2061
2057
  /**
2062
2058
  * A class that parses an OpenAPI specification file and provides methods to validate, list, and generate artifacts.
@@ -2354,25 +2350,11 @@ class SpecParser {
2354
2350
  if (this.options.allowMethods.includes(method)) {
2355
2351
  const operation = newSpec.paths[url][method];
2356
2352
  try {
2357
- const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
2353
+ const [card, jsonPath, jsonData, warnings] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
2354
+ result.warnings.push(...warnings);
2358
2355
  const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
2359
2356
  const fileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
2360
2357
  const wrappedCard = wrapAdaptiveCard(card, jsonPath);
2361
- const { json } = Utils.getResponseJson(operation, false);
2362
- const schema = json.schema;
2363
- let jsonData = {};
2364
- if (schema && Object.keys(schema).length > 0) {
2365
- try {
2366
- jsonData = JsonDataGenerator.generate(schema);
2367
- }
2368
- catch (err) {
2369
- result.warnings.push({
2370
- type: WarningType.GenerateJsonDataFailed,
2371
- content: Utils.format(ConstantString.GenerateJsonDataFailed, operation.operationId, err.toString()),
2372
- data: operation.operationId,
2373
- });
2374
- }
2375
- }
2376
2358
  await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
2377
2359
  const dataFileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
2378
2360
  await fs.outputJSON(dataFileName, jsonData, { spaces: 2 });