@microsoft/m365-spec-parser 0.2.2-alpha.8020c3125.0 → 0.2.2-alpha.82b9276fd.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.
@@ -3,6 +3,7 @@ import converter from 'swagger2openapi';
3
3
  import jsyaml from 'js-yaml';
4
4
  import fs from 'fs-extra';
5
5
  import path from 'path';
6
+ import { createHash } from 'crypto';
6
7
 
7
8
  // Copyright (c) Microsoft Corporation.
8
9
  /**
@@ -58,6 +59,7 @@ var WarningType;
58
59
  WarningType["GenerateCardFailed"] = "generate-card-failed";
59
60
  WarningType["OperationOnlyContainsOptionalParam"] = "operation-only-contains-optional-param";
60
61
  WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
62
+ WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
61
63
  WarningType["Unknown"] = "unknown";
62
64
  })(WarningType || (WarningType = {}));
63
65
  /**
@@ -96,6 +98,7 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
96
98
  ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
97
99
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
98
100
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
101
+ ConstantString.FuncDescriptionTooLong = "The description of the function '%s' is too long. The current length is %s characters, while the maximum allowed length is %s characters.";
99
102
  ConstantString.WrappedCardVersion = "devPreview";
100
103
  ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
101
104
  ConstantString.WrappedCardResponseLayout = "list";
@@ -175,6 +178,7 @@ ConstantString.ConversationStarterMaxLens = 50;
175
178
  ConstantString.CommandTitleMaxLens = 32;
176
179
  ConstantString.ParameterTitleMaxLens = 32;
177
180
  ConstantString.SMERequiredParamsMaxNum = 5;
181
+ ConstantString.FunctionDescriptionMaxLens = 100;
178
182
  ConstantString.DefaultPluginId = "plugin_1";
179
183
  ConstantString.PluginManifestSchema = "https://aka.ms/json-schemas/copilot-extensions/v2.1/plugin.schema.json";
180
184
 
@@ -260,23 +264,28 @@ class Utils {
260
264
  return str.charAt(0).toUpperCase() + str.slice(1);
261
265
  }
262
266
  static getResponseJson(operationObject, allowMultipleMediaType = false) {
263
- var _a, _b;
267
+ var _a;
264
268
  let json = {};
265
269
  let multipleMediaType = false;
266
270
  for (const code of ConstantString.ResponseCodeFor20X) {
267
271
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
268
- if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
269
- multipleMediaType = false;
270
- json = responseObject.content["application/json"];
271
- if (Utils.containMultipleMediaTypes(responseObject)) {
272
- multipleMediaType = true;
273
- if (!allowMultipleMediaType) {
274
- json = {};
272
+ if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
273
+ for (const contentType of Object.keys(responseObject.content)) {
274
+ // json media type can also be "application/json; charset=utf-8"
275
+ if (contentType.indexOf("application/json") >= 0) {
276
+ multipleMediaType = false;
277
+ json = responseObject.content[contentType];
278
+ if (Utils.containMultipleMediaTypes(responseObject)) {
279
+ multipleMediaType = true;
280
+ if (!allowMultipleMediaType) {
281
+ json = {};
282
+ }
283
+ }
284
+ else {
285
+ return { json, multipleMediaType };
286
+ }
275
287
  }
276
288
  }
277
- else {
278
- break;
279
- }
280
289
  }
281
290
  }
282
291
  return { json, multipleMediaType };
@@ -550,10 +559,11 @@ class Utils {
550
559
  currentCount += items.length;
551
560
  }
552
561
  else {
553
- if (currentCount < maxCount) {
554
- result.push(element);
555
- currentCount++;
556
- }
562
+ result.push(element);
563
+ currentCount++;
564
+ }
565
+ if (currentCount >= maxCount) {
566
+ break;
557
567
  }
558
568
  }
559
569
  return result;
@@ -1590,7 +1600,7 @@ function inferProperties(card) {
1590
1600
 
1591
1601
  // Copyright (c) Microsoft Corporation.
1592
1602
  class ManifestUpdater {
1593
- static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authInfo) {
1603
+ static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authInfo, existingPluginManifestInfo) {
1594
1604
  const manifest = await fs.readJSON(manifestPath);
1595
1605
  const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
1596
1606
  manifest.copilotExtensions = manifest.copilotExtensions || {};
@@ -1606,7 +1616,7 @@ class ManifestUpdater {
1606
1616
  }
1607
1617
  const appName = this.removeEnvs(manifest.name.short);
1608
1618
  const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
1609
- const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options);
1619
+ const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo);
1610
1620
  return [manifest, apiPlugin, warnings];
1611
1621
  }
1612
1622
  static updateManifestDescription(manifest, spec) {
@@ -1628,7 +1638,7 @@ class ManifestUpdater {
1628
1638
  throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
1629
1639
  }
1630
1640
  }
1631
- static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options) {
1641
+ static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authInfo, options, existingPluginManifestInfo) {
1632
1642
  var _a, _b, _c, _d;
1633
1643
  const warnings = [];
1634
1644
  const functions = [];
@@ -1687,9 +1697,18 @@ class ManifestUpdater {
1687
1697
  throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
1688
1698
  }
1689
1699
  }
1700
+ let funcDescription = operationItem.description || operationItem.summary || "";
1701
+ if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
1702
+ warnings.push({
1703
+ type: WarningType.FuncDescriptionTooLong,
1704
+ content: Utils.format(ConstantString.FuncDescriptionTooLong, safeFunctionName, funcDescription.length.toString(), ConstantString.FunctionDescriptionMaxLens.toString()),
1705
+ data: safeFunctionName,
1706
+ });
1707
+ funcDescription = funcDescription.slice(0, ConstantString.FunctionDescriptionMaxLens);
1708
+ }
1690
1709
  const funcObj = {
1691
1710
  name: safeFunctionName,
1692
- description: description,
1711
+ description: funcDescription,
1693
1712
  };
1694
1713
  if (options.allowResponseSemantics) {
1695
1714
  try {
@@ -1738,6 +1757,10 @@ class ManifestUpdater {
1738
1757
  if (await fs.pathExists(apiPluginFilePath)) {
1739
1758
  apiPlugin = await fs.readJSON(apiPluginFilePath);
1740
1759
  }
1760
+ else if (existingPluginManifestInfo &&
1761
+ (await fs.pathExists(existingPluginManifestInfo.manifestPath))) {
1762
+ apiPlugin = await fs.readJSON(existingPluginManifestInfo.manifestPath);
1763
+ }
1741
1764
  else {
1742
1765
  apiPlugin = {
1743
1766
  $schema: ConstantString.PluginManifestSchema,
@@ -1760,6 +1783,11 @@ class ManifestUpdater {
1760
1783
  }
1761
1784
  }
1762
1785
  apiPlugin.runtimes = apiPlugin.runtimes || [];
1786
+ // Need to delete previous runtime since spec path has changed
1787
+ if (existingPluginManifestInfo) {
1788
+ const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
1789
+ apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
1790
+ }
1763
1791
  const index = apiPlugin.runtimes.findIndex((runtime) => {
1764
1792
  var _a, _b;
1765
1793
  return runtime.spec.url === specRelativePath &&
@@ -1956,6 +1984,7 @@ class SpecParser {
1956
1984
  */
1957
1985
  async validate() {
1958
1986
  try {
1987
+ let hash = "";
1959
1988
  try {
1960
1989
  await this.loadSpec();
1961
1990
  if (!this.parser.$refs.circular) {
@@ -1971,8 +2000,13 @@ class SpecParser {
1971
2000
  status: ValidationStatus.Error,
1972
2001
  warnings: [],
1973
2002
  errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
2003
+ specHash: hash,
1974
2004
  };
1975
2005
  }
2006
+ if (this.unResolveSpec.servers) {
2007
+ const serverString = JSON.stringify(this.unResolveSpec.servers);
2008
+ hash = createHash("sha256").update(serverString).digest("hex");
2009
+ }
1976
2010
  const errors = [];
1977
2011
  const warnings = [];
1978
2012
  if (!this.options.allowSwagger && this.isSwaggerFile) {
@@ -1982,6 +2016,7 @@ class SpecParser {
1982
2016
  errors: [
1983
2017
  { type: ErrorType.SwaggerNotSupported, content: ConstantString.SwaggerNotSupported },
1984
2018
  ],
2019
+ specHash: hash,
1985
2020
  };
1986
2021
  }
1987
2022
  // Remote reference not supported
@@ -2015,6 +2050,7 @@ class SpecParser {
2015
2050
  status: status,
2016
2051
  warnings: warnings,
2017
2052
  errors: errors,
2053
+ specHash: hash,
2018
2054
  };
2019
2055
  }
2020
2056
  catch (err) {
@@ -2130,7 +2166,7 @@ class SpecParser {
2130
2166
  * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
2131
2167
  * @param pluginFilePath File path of the api plugin file to generate.
2132
2168
  */
2133
- async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
2169
+ async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, existingPluginFilePath, signal) {
2134
2170
  const result = {
2135
2171
  allSuccess: true,
2136
2172
  warnings: [],
@@ -2144,7 +2180,13 @@ class SpecParser {
2144
2180
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
2145
2181
  throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
2146
2182
  }
2147
- const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authInfo);
2183
+ const existingPluginManifestInfo = existingPluginFilePath
2184
+ ? {
2185
+ manifestPath: existingPluginFilePath,
2186
+ specPath: this.pathOrSpec,
2187
+ }
2188
+ : undefined;
2189
+ const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authInfo, existingPluginManifestInfo);
2148
2190
  result.warnings.push(...warnings);
2149
2191
  await fs.outputJSON(manifestPath, updatedManifest, { spaces: 4 });
2150
2192
  await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });