diff --git a/.github/shared/src/spec-model.js b/.github/shared/src/spec-model.js index 53f3fb404e3d..77805d7f25b5 100644 --- a/.github/shared/src/spec-model.js +++ b/.github/shared/src/spec-model.js @@ -5,6 +5,9 @@ import { resolve } from "path"; import { flatMapAsync, mapAsync } from "./array.js"; import { Readme } from "./readme.js"; +/** @type {Map} */ +const specModelCache = new Map(); + /** * @typedef {Object} ToJSONOptions * @prop {boolean} [includeRefs] @@ -16,6 +19,7 @@ import { Readme } from "./readme.js"; export class SpecModel { /** @type {string} absolute path */ + // @ts-ignore Ignore error that value may not be set in ctor (since we may returned cached value) #folder; /** @type {import('./logger.js').ILogger | undefined} */ @@ -30,8 +34,17 @@ export class SpecModel { * @param {import('./logger.js').ILogger} [options.logger] */ constructor(folder, options) { - this.#folder = resolve(folder); + const resolvedFolder = resolve(folder); + + const cachedSpecModel = specModelCache.get(resolvedFolder); + if (cachedSpecModel !== undefined) { + return cachedSpecModel; + } + + this.#folder = resolvedFolder; this.#logger = options?.logger; + + specModelCache.set(resolvedFolder, this); } /** diff --git a/.github/shared/test/spec-model.test.js b/.github/shared/test/spec-model.test.js index 128b563d3dd9..83413d93854c 100644 --- a/.github/shared/test/spec-model.test.js +++ b/.github/shared/test/spec-model.test.js @@ -1,5 +1,6 @@ // @ts-check +import { randomUUID } from "crypto"; import { readdir } from "fs/promises"; import { dirname, isAbsolute, join, resolve } from "path"; import { describe, expect, it } from "vitest"; @@ -18,6 +19,15 @@ describe("SpecModel", () => { await expect(specModel.getReadmes()).rejects.toThrowError(/no such file or directory/i); }); + it("returns cached spec model", async () => { + const path = randomUUID(); + + const specModel1 = new SpecModel(path); + const specModel2 = new SpecModel(path); + + expect(specModel1).toBe(specModel2); + }); + it("returns spec model", async () => { const folder = resolve( __dirname, diff --git a/.github/shared/test/swagger.test.js b/.github/shared/test/swagger.test.js index 13bb7ca53a55..abca25fe9ffb 100644 --- a/.github/shared/test/swagger.test.js +++ b/.github/shared/test/swagger.test.js @@ -1,14 +1,14 @@ // @ts-check -import { dirname, resolve, join } from "path"; +import { dirname, join, resolve } from "path"; import { describe, expect, it } from "vitest"; import { Swagger } from "../src/swagger.js"; import { fileURLToPath } from "url"; +import { ConsoleLogger } from "../src/logger.js"; import { Readme } from "../src/readme.js"; -import { Tag } from "../src/tag.js"; import { SpecModel } from "../src/spec-model.js"; -import { ConsoleLogger } from "../src/logger.js"; +import { Tag } from "../src/tag.js"; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -51,6 +51,26 @@ describe("Swagger", () => { ); }); + it("returns examples", async () => { + const swagger = new Swagger(resolve(__dirname, "fixtures/swagger/ignoreExamples/swagger.json")); + const examples = await swagger.getExamples(); + + const expectedExamplePath = resolve( + __dirname, + "fixtures/swagger/ignoreExamples/examples/example.json", + ); + expect(examples).toMatchObject( + new Map([ + [ + expectedExamplePath, + expect.objectContaining({ + path: expect.stringContaining(expectedExamplePath), + }), + ], + ]), + ); + }); + describe("getOperations", () => { it("should return normal operations", async () => { const testFixturePath = join(__dirname, "fixtures", "swagger", "specification");