Skip to content

Commit

Permalink
perf(spec parser): update spec parser for teams ai template (#10952)
Browse files Browse the repository at this point in the history
* perf(spec parser): update spec parser for teams ai template

* docs: update comment

* perf: update generate for browser
  • Loading branch information
KennethBWSong authored Feb 29, 2024
1 parent 889742a commit fccd829
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 17 deletions.
2 changes: 2 additions & 0 deletions packages/spec-parser/src/index.browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export type {
ValidateResult,
WarningResult,
ParseOptions,
AdaptiveCard,
} from "./interfaces";
export { ConstantString } from "./constants";
export { Utils } from "./utils";
export { AdaptiveCardGenerator } from "./adaptiveCardGenerator";
2 changes: 2 additions & 0 deletions packages/spec-parser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ export {
APIInfo,
ValidateResult,
ParseOptions,
AdaptiveCard,
} from "./interfaces";

export { ConstantString } from "./constants";
export { Utils } from "./utils";
export { AdaptiveCardGenerator } from "./adaptiveCardGenerator";
1 change: 1 addition & 0 deletions packages/spec-parser/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 3 additions & 2 deletions packages/spec-parser/src/manifestUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -74,7 +75,7 @@ export class ManifestUpdater {
),
};

updatedPart.composeExtensions = [composeExtension];
updatedPart.composeExtensions = isMe === undefined || isMe === true ? [composeExtension] : [];

const updatedManifest = { ...originalManifest, ...updatedPart };

Expand Down
16 changes: 15 additions & 1 deletion packages/spec-parser/src/specParser.browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,20 +151,34 @@ 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(
manifestPath: string,
filter: string[],
outputSpecPath: string,
adaptiveCardFolder: string,
signal?: AbortSignal
signal?: AbortSignal,
isMe?: boolean
): Promise<GenerateResult> {
throw new Error("Method not implemented.");
}
Expand Down
52 changes: 38 additions & 14 deletions packages/spec-parser/src/specParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<GenerateResult> {
const result: GenerateResult = {
allSuccess: true,
warnings: [],
};
): Promise<[OpenAPIV3.Document, OpenAPIV3.Document]> {
try {
if (signal?.aborted) {
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
Expand All @@ -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<GenerateResult> {
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<OpenAPIV3.SecuritySchemeObject> = new Set();
let hasMultipleAPIKeyAuth = false;
Expand Down Expand Up @@ -285,7 +308,8 @@ export class SpecParser {
adaptiveCardFolder,
newSpec,
this.options.allowMultipleParameters,
auth
auth,
isMe
);

await fs.outputJSON(manifestPath, updatedManifest, { spaces: 2 });
Expand Down
31 changes: 31 additions & 0 deletions packages/spec-parser/test/manifestUpdater.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down
17 changes: 17 additions & 0 deletions packages/spec-parser/test/specParser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
});
});
});

0 comments on commit fccd829

Please sign in to comment.