@microsoft/m365-spec-parser 0.1.1-alpha.f4dd51600.0 → 0.1.1-alpha.fbb412c19.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.
@@ -83,7 +83,7 @@ ConstantString.RemoteRefNotSupported = "Remote reference is not supported: %s.";
83
83
  ConstantString.MissingOperationId = "Missing operationIds: %s.";
84
84
  ConstantString.NoSupportedApi = "No supported API is found in the OpenAPI description document: only GET and POST methods are supported, additionally, there can be at most one required parameter, and no auth is allowed.";
85
85
  ConstantString.AdditionalPropertiesNotSupported = "'additionalProperties' is not supported, and will be ignored.";
86
- ConstantString.SchemaNotSupported = "'oneOf', 'anyOf', and 'not' schema are not supported: %s.";
86
+ ConstantString.SchemaNotSupported = "'oneOf', 'allOf', 'anyOf', and 'not' schema are not supported: %s.";
87
87
  ConstantString.UnknownSchema = "Unknown schema: %s.";
88
88
  ConstantString.UrlProtocolNotSupported = "Server url is not correct: protocol %s is not supported, you should use https protocol instead.";
89
89
  ConstantString.RelativeServerUrlNotSupported = "Server url is not correct: relative server url is not supported.";
@@ -105,8 +105,12 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
105
105
  ConstantString.TextBlockType = "TextBlock";
106
106
  ConstantString.ImageType = "Image";
107
107
  ConstantString.ContainerType = "Container";
108
- ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
109
- ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
108
+ ConstantString.RegistrationIdPostfix = {
109
+ apiKey: "REGISTRATION_ID",
110
+ oauth2: "CONFIGURATION_ID",
111
+ http: "REGISTRATION_ID",
112
+ openIdConnect: "REGISTRATION_ID",
113
+ };
110
114
  ConstantString.ResponseCodeFor20X = [
111
115
  "200",
112
116
  "201",
@@ -165,6 +169,7 @@ ConstantString.ShortDescriptionMaxLens = 80;
165
169
  ConstantString.FullDescriptionMaxLens = 4000;
166
170
  ConstantString.CommandDescriptionMaxLens = 128;
167
171
  ConstantString.ParameterDescriptionMaxLens = 128;
172
+ ConstantString.ConversationStarterMaxLens = 50;
168
173
  ConstantString.CommandTitleMaxLens = 32;
169
174
  ConstantString.ParameterTitleMaxLens = 32;
170
175
  ConstantString.SMERequiredParamsMaxNum = 5;
@@ -209,9 +214,10 @@ class Utils {
209
214
  var _a;
210
215
  const result = [];
211
216
  const securitySchemas = (_a = spec.components) === null || _a === void 0 ? void 0 : _a.securitySchemes;
212
- if (securities && securitySchemas) {
213
- for (let i = 0; i < securities.length; i++) {
214
- const security = securities[i];
217
+ const securitiesArr = securities !== null && securities !== void 0 ? securities : spec.security;
218
+ if (securitiesArr && securitySchemas) {
219
+ for (let i = 0; i < securitiesArr.length; i++) {
220
+ const security = securitiesArr[i];
215
221
  const authArray = [];
216
222
  for (const name in security) {
217
223
  const auth = securitySchemas[name];
@@ -228,6 +234,25 @@ class Utils {
228
234
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
229
235
  return result;
230
236
  }
237
+ static getAuthInfo(spec) {
238
+ let authInfo = undefined;
239
+ for (const url in spec.paths) {
240
+ for (const method in spec.paths[url]) {
241
+ const operation = spec.paths[url][method];
242
+ const authArray = Utils.getAuthArray(operation.security, spec);
243
+ if (authArray && authArray.length > 0) {
244
+ const currentAuth = authArray[0][0];
245
+ if (!authInfo) {
246
+ authInfo = authArray[0][0];
247
+ }
248
+ else if (authInfo.name !== currentAuth.name) {
249
+ throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
250
+ }
251
+ }
252
+ }
253
+ }
254
+ return authInfo;
255
+ }
231
256
  static updateFirstLetter(str) {
232
257
  return str.charAt(0).toUpperCase() + str.slice(1);
233
258
  }
@@ -609,13 +634,15 @@ class Validator {
609
634
  const result = { isValid: true, reason: [] };
610
635
  const operationObject = this.spec.paths[path][method];
611
636
  const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
612
- // only support response body only contains “application/json” content type
613
- if (multipleMediaType) {
614
- result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
615
- }
616
- else if (Object.keys(json).length === 0) {
617
- // response body should not be empty
618
- result.reason.push(ErrorType.ResponseJsonIsEmpty);
637
+ if (this.options.projectType === ProjectType.SME) {
638
+ // only support response body only contains “application/json” content type
639
+ if (multipleMediaType) {
640
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
641
+ }
642
+ else if (Object.keys(json).length === 0) {
643
+ // response body should not be empty
644
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
645
+ }
619
646
  }
620
647
  return result;
621
648
  }
@@ -833,9 +860,6 @@ class CopilotValidator extends Validator {
833
860
  // validate requestBody
834
861
  const requestBody = operationObject.requestBody;
835
862
  const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
836
- if (Utils.containMultipleMediaTypes(requestBody)) {
837
- result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
838
- }
839
863
  if (requestJsonBody) {
840
864
  const requestBodySchema = requestJsonBody.schema;
841
865
  if (requestBodySchema.type !== "object") {
@@ -1340,19 +1364,22 @@ function inferProperties(card) {
1340
1364
 
1341
1365
  // Copyright (c) Microsoft Corporation.
1342
1366
  class ManifestUpdater {
1343
- static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options) {
1367
+ static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authInfo) {
1344
1368
  const manifest = await fs.readJSON(manifestPath);
1345
1369
  const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
1346
- manifest.plugins = [
1347
- {
1348
- file: apiPluginRelativePath,
1349
- id: ConstantString.DefaultPluginId,
1350
- },
1351
- ];
1370
+ // Insert plugins in manifest.json if it is plugin for Copilot.
1371
+ if (!options.isGptPlugin) {
1372
+ manifest.plugins = [
1373
+ {
1374
+ file: apiPluginRelativePath,
1375
+ id: ConstantString.DefaultPluginId,
1376
+ },
1377
+ ];
1378
+ ManifestUpdater.updateManifestDescription(manifest, spec);
1379
+ }
1352
1380
  const appName = this.removeEnvs(manifest.name.short);
1353
- ManifestUpdater.updateManifestDescription(manifest, spec);
1354
1381
  const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
1355
- const apiPlugin = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, options);
1382
+ const apiPlugin = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options);
1356
1383
  return [manifest, apiPlugin];
1357
1384
  }
1358
1385
  static updateManifestDescription(manifest, spec) {
@@ -1362,26 +1389,39 @@ class ManifestUpdater {
1362
1389
  full: (_b = ((_a = spec.info.description) !== null && _a !== void 0 ? _a : manifest.description.full)) === null || _b === void 0 ? void 0 : _b.slice(0, ConstantString.FullDescriptionMaxLens),
1363
1390
  };
1364
1391
  }
1365
- static mapOpenAPISchemaToFuncParam(schema, method, pathUrl) {
1366
- let parameter;
1367
- if (schema.type === "string" ||
1368
- schema.type === "boolean" ||
1369
- schema.type === "integer" ||
1370
- schema.type === "number" ||
1371
- schema.type === "array") {
1372
- parameter = schema;
1392
+ static checkSchema(schema, method, pathUrl) {
1393
+ if (schema.type === "array") {
1394
+ const items = schema.items;
1395
+ ManifestUpdater.checkSchema(items, method, pathUrl);
1373
1396
  }
1374
- else {
1397
+ else if (schema.type !== "string" &&
1398
+ schema.type !== "boolean" &&
1399
+ schema.type !== "integer" &&
1400
+ schema.type !== "number") {
1375
1401
  throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
1376
1402
  }
1377
- return parameter;
1378
1403
  }
1379
- static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, options) {
1404
+ static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options) {
1380
1405
  var _a, _b, _c, _d;
1381
1406
  const functions = [];
1382
1407
  const functionNames = [];
1383
1408
  const conversationStarters = [];
1384
1409
  const paths = spec.paths;
1410
+ const pluginAuthObj = {
1411
+ type: "None",
1412
+ };
1413
+ if (authInfo) {
1414
+ if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
1415
+ pluginAuthObj.type = "OAuthPluginVault";
1416
+ }
1417
+ else if (Utils.isBearerTokenAuth(authInfo.authScheme)) {
1418
+ pluginAuthObj.type = "ApiKeyPluginVault";
1419
+ }
1420
+ if (pluginAuthObj.type !== "None") {
1421
+ const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1422
+ pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
1423
+ }
1424
+ }
1385
1425
  for (const pathUrl in paths) {
1386
1426
  const pathItem = paths[pathUrl];
1387
1427
  if (pathItem) {
@@ -1389,39 +1429,29 @@ class ManifestUpdater {
1389
1429
  for (const method in operations) {
1390
1430
  if (options.allowMethods.includes(method)) {
1391
1431
  const operationItem = operations[method];
1432
+ const confirmationBodies = [];
1392
1433
  if (operationItem) {
1393
1434
  const operationId = operationItem.operationId;
1394
1435
  const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
1436
+ const summary = operationItem.summary;
1395
1437
  const paramObject = operationItem.parameters;
1396
1438
  const requestBody = operationItem.requestBody;
1397
- const parameters = {
1398
- type: "object",
1399
- properties: {},
1400
- required: [],
1401
- };
1402
1439
  if (paramObject) {
1403
1440
  for (let i = 0; i < paramObject.length; i++) {
1404
1441
  const param = paramObject[i];
1405
1442
  const schema = param.schema;
1406
- parameters.properties[param.name] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
1407
- if (param.required) {
1408
- parameters.required.push(param.name);
1409
- }
1410
- if (!parameters.properties[param.name].description) {
1411
- parameters.properties[param.name].description = (_b = param.description) !== null && _b !== void 0 ? _b : "";
1412
- }
1443
+ ManifestUpdater.checkSchema(schema, method, pathUrl);
1444
+ confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
1413
1445
  }
1414
1446
  }
1415
1447
  if (requestBody) {
1416
1448
  const requestJsonBody = requestBody.content["application/json"];
1417
1449
  const requestBodySchema = requestJsonBody.schema;
1418
1450
  if (requestBodySchema.type === "object") {
1419
- if (requestBodySchema.required) {
1420
- parameters.required.push(...requestBodySchema.required);
1421
- }
1422
1451
  for (const property in requestBodySchema.properties) {
1423
1452
  const schema = requestBodySchema.properties[property];
1424
- parameters.properties[property] = ManifestUpdater.mapOpenAPISchemaToFuncParam(schema, method, pathUrl);
1453
+ ManifestUpdater.checkSchema(schema, method, pathUrl);
1454
+ confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
1425
1455
  }
1426
1456
  }
1427
1457
  else {
@@ -1431,19 +1461,34 @@ class ManifestUpdater {
1431
1461
  const funcObj = {
1432
1462
  name: operationId,
1433
1463
  description: description,
1434
- parameters: parameters,
1435
1464
  };
1436
1465
  if (options.allowResponseSemantics) {
1437
- const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem);
1438
- const responseSemantic = wrapResponseSemantics(card, jsonPath);
1439
- funcObj.capabilities = {
1440
- response_semantics: responseSemantic,
1466
+ const { json } = Utils.getResponseJson(operationItem);
1467
+ if (json.schema) {
1468
+ const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem);
1469
+ const responseSemantic = wrapResponseSemantics(card, jsonPath);
1470
+ funcObj.capabilities = {
1471
+ response_semantics: responseSemantic,
1472
+ };
1473
+ }
1474
+ }
1475
+ if (options.allowConfirmation && method !== ConstantString.GetMethod) {
1476
+ if (!funcObj.capabilities) {
1477
+ funcObj.capabilities = {};
1478
+ }
1479
+ funcObj.capabilities.confirmation = {
1480
+ type: "AdaptiveCard",
1481
+ title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
1441
1482
  };
1483
+ if (confirmationBodies.length > 0) {
1484
+ funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
1485
+ }
1442
1486
  }
1443
1487
  functions.push(funcObj);
1444
1488
  functionNames.push(operationId);
1445
- if (description) {
1446
- conversationStarters.push(description);
1489
+ const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
1490
+ if (conversationStarterStr) {
1491
+ conversationStarters.push(conversationStarterStr);
1447
1492
  }
1448
1493
  }
1449
1494
  }
@@ -1456,9 +1501,10 @@ class ManifestUpdater {
1456
1501
  }
1457
1502
  else {
1458
1503
  apiPlugin = {
1459
- schema_version: "v2",
1504
+ schema_version: "v2.1",
1460
1505
  name_for_human: "",
1461
1506
  description_for_human: "",
1507
+ namespace: "",
1462
1508
  functions: [],
1463
1509
  runtimes: [],
1464
1510
  };
@@ -1474,13 +1520,16 @@ class ManifestUpdater {
1474
1520
  }
1475
1521
  }
1476
1522
  apiPlugin.runtimes = apiPlugin.runtimes || [];
1477
- const index = apiPlugin.runtimes.findIndex((runtime) => runtime.spec.url === specRelativePath);
1523
+ const index = apiPlugin.runtimes.findIndex((runtime) => {
1524
+ var _a, _b;
1525
+ return runtime.spec.url === specRelativePath &&
1526
+ runtime.type === "OpenApi" &&
1527
+ ((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === pluginAuthObj.type;
1528
+ });
1478
1529
  if (index === -1) {
1479
1530
  apiPlugin.runtimes.push({
1480
1531
  type: "OpenApi",
1481
- auth: {
1482
- type: "none",
1483
- },
1532
+ auth: pluginAuthObj,
1484
1533
  spec: {
1485
1534
  url: specRelativePath,
1486
1535
  },
@@ -1493,6 +1542,9 @@ class ManifestUpdater {
1493
1542
  if (!apiPlugin.name_for_human) {
1494
1543
  apiPlugin.name_for_human = appName;
1495
1544
  }
1545
+ if (!apiPlugin.namespace) {
1546
+ apiPlugin.namespace = ManifestUpdater.removeAllSpecialCharacters(appName);
1547
+ }
1496
1548
  if (!apiPlugin.description_for_human) {
1497
1549
  apiPlugin.description_for_human =
1498
1550
  (_d = spec.info.description) !== null && _d !== void 0 ? _d : "<Please add description of the plugin>";
@@ -1528,21 +1580,21 @@ class ManifestUpdater {
1528
1580
  };
1529
1581
  if (authInfo) {
1530
1582
  const auth = authInfo.authScheme;
1583
+ const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1531
1584
  if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
1532
- const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
1585
+ const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
1533
1586
  composeExtension.authorization = {
1534
1587
  authType: "apiSecretServiceAuth",
1535
1588
  apiSecretServiceAuthConfiguration: {
1536
- apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
1589
+ apiSecretRegistrationId: `\${{${safeRegistrationIdName}}}`,
1537
1590
  },
1538
1591
  };
1539
1592
  }
1540
1593
  else if (Utils.isOAuthWithAuthCodeFlow(auth)) {
1541
- const safeOAuth2RegistrationId = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.OAuthRegistrationIdPostFix}`);
1542
1594
  composeExtension.authorization = {
1543
1595
  authType: "oAuth2.0",
1544
1596
  oAuthConfiguration: {
1545
- oauthConfigurationId: `\${{${safeOAuth2RegistrationId}}}`,
1597
+ oauthConfigurationId: `\${{${safeRegistrationIdName}}}`,
1546
1598
  },
1547
1599
  };
1548
1600
  updatedPart.webApplicationInfo = {
@@ -1619,6 +1671,12 @@ class ManifestUpdater {
1619
1671
  }
1620
1672
  return newStr;
1621
1673
  }
1674
+ static removeAllSpecialCharacters(str) {
1675
+ return str.toLowerCase().replace(/[^a-z0-9]/g, "");
1676
+ }
1677
+ static getConfirmationBodyItem(paramName) {
1678
+ return `* **${Utils.updateFirstLetter(paramName)}**: {{function.parameters.${paramName}}}`;
1679
+ }
1622
1680
  }
1623
1681
 
1624
1682
  // Copyright (c) Microsoft Corporation.
@@ -1642,7 +1700,9 @@ class SpecParser {
1642
1700
  allowMethods: ["get", "post"],
1643
1701
  allowConversationStarters: false,
1644
1702
  allowResponseSemantics: false,
1703
+ allowConfirmation: false,
1645
1704
  projectType: ProjectType.SME,
1705
+ isGptPlugin: false,
1646
1706
  };
1647
1707
  this.pathOrSpec = pathOrDoc;
1648
1708
  this.parser = new SwaggerParser();
@@ -1814,18 +1874,12 @@ class SpecParser {
1814
1874
  const newSpecs = await this.getFilteredSpecs(filter, signal);
1815
1875
  const newUnResolvedSpec = newSpecs[0];
1816
1876
  const newSpec = newSpecs[1];
1817
- let resultStr;
1818
- if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1819
- resultStr = jsyaml.dump(newUnResolvedSpec);
1820
- }
1821
- else {
1822
- resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1823
- }
1824
- await fs.outputFile(outputSpecPath, resultStr);
1877
+ const authInfo = Utils.getAuthInfo(newSpec);
1878
+ await this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
1825
1879
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
1826
1880
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
1827
1881
  }
1828
- const [updatedManifest, apiPlugin] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options);
1882
+ const [updatedManifest, apiPlugin] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authInfo);
1829
1883
  await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
1830
1884
  await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 2 });
1831
1885
  }
@@ -1853,35 +1907,11 @@ class SpecParser {
1853
1907
  const newSpecs = await this.getFilteredSpecs(filter, signal);
1854
1908
  const newUnResolvedSpec = newSpecs[0];
1855
1909
  const newSpec = newSpecs[1];
1856
- let hasMultipleAuth = false;
1857
1910
  let authInfo = undefined;
1858
- for (const url in newSpec.paths) {
1859
- for (const method in newSpec.paths[url]) {
1860
- const operation = newSpec.paths[url][method];
1861
- const authArray = Utils.getAuthArray(operation.security, newSpec);
1862
- if (authArray && authArray.length > 0) {
1863
- const currentAuth = authArray[0][0];
1864
- if (!authInfo) {
1865
- authInfo = authArray[0][0];
1866
- }
1867
- else if (authInfo.name !== currentAuth.name) {
1868
- hasMultipleAuth = true;
1869
- break;
1870
- }
1871
- }
1872
- }
1873
- }
1874
- if (hasMultipleAuth && this.options.projectType !== ProjectType.TeamsAi) {
1875
- throw new SpecParserError(ConstantString.MultipleAuthNotSupported, ErrorType.MultipleAuthNotSupported);
1876
- }
1877
- let resultStr;
1878
- if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1879
- resultStr = jsyaml.dump(newUnResolvedSpec);
1911
+ if (this.options.projectType === ProjectType.SME) {
1912
+ authInfo = Utils.getAuthInfo(newSpec);
1880
1913
  }
1881
- else {
1882
- resultStr = JSON.stringify(newUnResolvedSpec, null, 2);
1883
- }
1884
- await fs.outputFile(outputSpecPath, resultStr);
1914
+ await this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
1885
1915
  if (adaptiveCardFolder) {
1886
1916
  for (const url in newSpec.paths) {
1887
1917
  for (const method in newSpec.paths[url]) {
@@ -1949,6 +1979,16 @@ class SpecParser {
1949
1979
  this.validator = validator;
1950
1980
  return validator;
1951
1981
  }
1982
+ async saveFilterSpec(outputSpecPath, unResolvedSpec) {
1983
+ let resultStr;
1984
+ if (outputSpecPath.endsWith(".yaml") || outputSpecPath.endsWith(".yml")) {
1985
+ resultStr = jsyaml.dump(unResolvedSpec);
1986
+ }
1987
+ else {
1988
+ resultStr = JSON.stringify(unResolvedSpec, null, 2);
1989
+ }
1990
+ await fs.outputFile(outputSpecPath, resultStr);
1991
+ }
1952
1992
  }
1953
1993
 
1954
1994
  export { AdaptiveCardGenerator, ConstantString, ErrorType, ProjectType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };