diff --git a/packages/spec-parser/src/index.browser.ts b/packages/spec-parser/src/index.browser.ts index 7da15cd3e8..af8207c636 100644 --- a/packages/spec-parser/src/index.browser.ts +++ b/packages/spec-parser/src/index.browser.ts @@ -11,6 +11,8 @@ export type { ValidateResult, WarningResult, ParseOptions, + AdaptiveCard, } from "./interfaces"; export { ConstantString } from "./constants"; export { Utils } from "./utils"; +export { AdaptiveCardGenerator } from "./adaptiveCardGenerator"; diff --git a/packages/spec-parser/src/index.ts b/packages/spec-parser/src/index.ts index c647f04569..929202f9dc 100644 --- a/packages/spec-parser/src/index.ts +++ b/packages/spec-parser/src/index.ts @@ -14,7 +14,9 @@ export { APIInfo, ValidateResult, ParseOptions, + AdaptiveCard, } from "./interfaces"; export { ConstantString } from "./constants"; export { Utils } from "./utils"; +export { AdaptiveCardGenerator } from "./adaptiveCardGenerator"; diff --git a/packages/spec-parser/src/interfaces.ts b/packages/spec-parser/src/interfaces.ts index dc4d5b2a63..4ec23b7fd1 100644 --- a/packages/spec-parser/src/interfaces.ts +++ b/packages/spec-parser/src/interfaces.ts @@ -91,6 +91,7 @@ export enum ErrorType { GenerateAdaptiveCardFailed = "generate-adaptive-card-failed", GenerateFailed = "generate-failed", ValidateFailed = "validate-failed", + GetSpecFailed = "get-spec-failed", Cancelled = "cancelled", Unknown = "unknown", diff --git a/packages/spec-parser/src/manifestUpdater.ts b/packages/spec-parser/src/manifestUpdater.ts index f44dcc218a..83bd4623b4 100644 --- a/packages/spec-parser/src/manifestUpdater.ts +++ b/packages/spec-parser/src/manifestUpdater.ts @@ -22,7 +22,8 @@ export class ManifestUpdater { adaptiveCardFolder: string, spec: OpenAPIV3.Document, allowMultipleParameters: boolean, - auth?: OpenAPIV3.SecuritySchemeObject + auth?: OpenAPIV3.SecuritySchemeObject, + isMe?: boolean ): Promise<[TeamsAppManifest, WarningResult[]]> { try { const originalManifest: TeamsAppManifest = await fs.readJSON(manifestPath); @@ -74,7 +75,7 @@ export class ManifestUpdater { ), }; - updatedPart.composeExtensions = [composeExtension]; + updatedPart.composeExtensions = isMe === undefined || isMe === true ? [composeExtension] : []; const updatedManifest = { ...originalManifest, ...updatedPart }; diff --git a/packages/spec-parser/src/specParser.browser.ts b/packages/spec-parser/src/specParser.browser.ts index ac5506032e..a4edf2e588 100644 --- a/packages/spec-parser/src/specParser.browser.ts +++ b/packages/spec-parser/src/specParser.browser.ts @@ -151,12 +151,25 @@ export class SpecParser { throw new Error("Method not implemented."); } + /** + * Generate specs according to the filters. + * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing. + */ + // eslint-disable-next-line @typescript-eslint/require-await + async getFilteredSpecs( + filter: string[], + signal?: AbortSignal + ): Promise<[OpenAPIV3.Document, OpenAPIV3.Document]> { + throw new Error("Method not implemented."); + } + /** * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file. * @param manifestPath A file path of the Teams app manifest file to update. * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing. * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated. * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated. + * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest. */ // eslint-disable-next-line @typescript-eslint/require-await async generate( @@ -164,7 +177,8 @@ export class SpecParser { filter: string[], outputSpecPath: string, adaptiveCardFolder: string, - signal?: AbortSignal + signal?: AbortSignal, + isMe?: boolean ): Promise { throw new Error("Method not implemented."); } diff --git a/packages/spec-parser/src/specParser.ts b/packages/spec-parser/src/specParser.ts index a08b7b0463..0ee2dbca4f 100644 --- a/packages/spec-parser/src/specParser.ts +++ b/packages/spec-parser/src/specParser.ts @@ -170,23 +170,13 @@ export class SpecParser { } /** - * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file. - * @param manifestPath A file path of the Teams app manifest file to update. + * Generate specs according to the filters. * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing. - * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated. - * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated. */ - async generate( - manifestPath: string, + async getFilteredSpecs( filter: string[], - outputSpecPath: string, - adaptiveCardFolder: string, signal?: AbortSignal - ): Promise { - const result: GenerateResult = { - allSuccess: true, - warnings: [], - }; + ): Promise<[OpenAPIV3.Document, OpenAPIV3.Document]> { try { if (signal?.aborted) { throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled); @@ -212,6 +202,39 @@ export class SpecParser { } const newSpec = (await this.parser.dereference(newUnResolvedSpec)) as OpenAPIV3.Document; + return [newUnResolvedSpec, newSpec]; + } catch (err) { + if (err instanceof SpecParserError) { + throw err; + } + throw new SpecParserError((err as Error).toString(), ErrorType.GetSpecFailed); + } + } + + /** + * Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file. + * @param manifestPath A file path of the Teams app manifest file to update. + * @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing. + * @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated. + * @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated. + * @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest. + */ + async generate( + manifestPath: string, + filter: string[], + outputSpecPath: string, + adaptiveCardFolder: string, + signal?: AbortSignal, + isMe?: boolean + ): Promise { + const result: GenerateResult = { + allSuccess: true, + warnings: [], + }; + try { + const newSpecs = await this.getFilteredSpecs(filter, signal); + const newUnResolvedSpec = newSpecs[0]; + const newSpec = newSpecs[1]; const AuthSet: Set = new Set(); let hasMultipleAPIKeyAuth = false; @@ -285,7 +308,8 @@ export class SpecParser { adaptiveCardFolder, newSpec, this.options.allowMultipleParameters, - auth + auth, + isMe ); await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 }); diff --git a/packages/spec-parser/test/manifestUpdater.test.ts b/packages/spec-parser/test/manifestUpdater.test.ts index e0823abf0c..3487eeaf96 100644 --- a/packages/spec-parser/test/manifestUpdater.test.ts +++ b/packages/spec-parser/test/manifestUpdater.test.ts @@ -984,6 +984,37 @@ describe("manifestUpdater", () => { expect(warnings).to.deep.equal([]); readJSONStub.restore(); }); + + it("should not update manifest if is not me", async () => { + const manifestPath = "/path/to/your/manifest.json"; + const outputSpecPath = "/path/to/your/spec/outputSpec.yaml"; + const adaptiveCardFolder = "/path/to/your/adaptiveCards"; + sinon.stub(fs, "pathExists").resolves(true); + const originalManifest = { + name: { short: "Original Name", full: "Original Full Name" }, + description: { short: "Original Short Description", full: "Original Full Description" }, + composeExtensions: [], + }; + const expectedManifest = { + name: { short: "Original Name", full: "Original Full Name" }, + description: { short: spec.info.title, full: spec.info.description }, + composeExtensions: [], + }; + const readJSONStub = sinon.stub(fs, "readJSON").resolves(originalManifest); + + const [result, warnings] = await ManifestUpdater.updateManifest( + manifestPath, + outputSpecPath, + adaptiveCardFolder, + spec, + false, + undefined, + false + ); + + expect(result).to.deep.equal(expectedManifest); + expect(warnings).to.deep.equal([]); + }); }); describe("getRelativePath", () => { diff --git a/packages/spec-parser/test/specParser.test.ts b/packages/spec-parser/test/specParser.test.ts index e51a1d4c49..1fb44afa84 100644 --- a/packages/spec-parser/test/specParser.test.ts +++ b/packages/spec-parser/test/specParser.test.ts @@ -1827,4 +1827,21 @@ describe("SpecParser", () => { ]); }); }); + + describe("getFilteredSpecs", () => { + it("should throw an error if failed to parse the spec", async () => { + const specParser = new SpecParser("path/to/spec.yaml"); + const spec = { openapi: "3.0.0", paths: {} }; + const parseStub = sinon.stub(specParser.parser, "parse").throws(new Error("parse error")); + const filter = ["get /hello"]; + try { + await specParser.getFilteredSpecs(filter); + expect.fail("Expected generate to throw a SpecParserError"); + } catch (err: any) { + expect(err).to.be.instanceOf(SpecParserError); + expect(err.errorType).to.equal(ErrorType.GetSpecFailed); + expect(err.message).to.equal("Error: parse error"); + } + }); + }); });