diff --git a/.changeset/thin-dolls-dance.md b/.changeset/thin-dolls-dance.md new file mode 100644 index 0000000000..a28631054d --- /dev/null +++ b/.changeset/thin-dolls-dance.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa-oas-cli": patch +--- + +feat(oas): new medusa-oas docs for Redocly and circular references diff --git a/packages/oas/medusa-oas-cli/README.md b/packages/oas/medusa-oas-cli/README.md index 103fd4756f..9ab334cef1 100644 --- a/packages/oas/medusa-oas-cli/README.md +++ b/packages/oas/medusa-oas-cli/README.md @@ -93,40 +93,127 @@ Will generate API client files from a given OAS file. Specify the path to the OAS JSON file. -`yarm medusa-oas client --src-file ./store.oas.json` +```bash +yarn medusa-oas client --src-file ./store.oas.json` +``` #### `--name ` Namespace for the generated client. Usually `admin` or `store`. -`yarm medusa-oas client --name admin` +```bash +yarn medusa-oas client --name admin` +``` #### `--out-dir ` -Specify in which directory should the files be outputted. Accepts relative and absolute path. It the directory doesn't -exist, it will be created. Defaults to `./`. +Specify in which directory should the files be outputted. Accepts relative and absolute path. +If the directory doesn't exist, it will be created. Defaults to `./`. -`yarm medusa-oas client --out-dir ./client` +```bash +yarn medusa-oas client --out-dir ./client` +``` #### `--type ` Client component types to generate. Accepts `all`, `types`, `client`, `hooks`. Defaults to `all`. -`yarn medusa-oas client --type types` +```bash +yarn medusa-oas client --type types` +``` #### `--types-packages ` Replace relative import statements by types package name. Mandatory when using `--type client` or `--type hooks`. +```bash +yarn medusa-oas client --types-packages @medusajs/client-types` +``` + #### `--client-packages ` Replace relative import statements by client package name. Mandatory when using `--type hooks`. -`yarn medusa-oas client --type types` +```bash +yarn medusa-oas client --client-packages @medusajs/medusa-js` +``` #### `--clean` Delete destination directory content before generating client. -`yarn medusa-oas --clean` +```bash +yarn medusa-oas client --clean +``` + +--- + +### Command - `docs` + +Will sanitize OAS for use with Redocly's API documentation viewer. + +#### `--src-file ` + +Specify the path to the OAS JSON file. + +```bash +yarm medusa-oas docs --src-file ./store.oas.json +``` + +#### `--out-dir ` + +Specify in which directory should the files be outputted. Accepts relative and absolute path. +If the directory doesn't exist, it will be created. Defaults to `./`. + +```bash +yarn medusa-oas docs --out-dir ./docs` +``` + +#### `--config ` + +Specify the path to a Redocly config file. + +```bash +yarn medusa-oas --config ./redocly-config.yaml +``` + +#### `--dry-run` + +Will sanitize the OAS but will not output file. Useful for troubleshooting circular reference issues. + +```bash +yarn medusa-oas docs --dry-run +``` + +#### `--clean` + +Delete destination directory content before generating client. + +```bash +yarn medusa-oas docs --clean +``` + +#### `--split` + +Creates a multi-file structure output. Uses `redocly split` internally. + +```bash +yarn medusa-oas docs --split +``` + +#### `--preview` + +Generate a preview of the API documentation in a browser. Does not output files. Uses `redocly preview-docs` internally. + +```bash +yarn medusa-oas docs --preview +``` + +#### `--html` + +Generate a zero-dependency static HTML file. Uses `redocly build-docs` internally. + +```bash +yarn medusa-oas docs --html +``` diff --git a/packages/oas/medusa-oas-cli/jest.config.js b/packages/oas/medusa-oas-cli/jest.config.js index 8cdcf8d10f..8e2c7bbc49 100644 --- a/packages/oas/medusa-oas-cli/jest.config.js +++ b/packages/oas/medusa-oas-cli/jest.config.js @@ -1,14 +1,14 @@ module.exports = { - globals: { - "ts-jest": { - tsConfig: "tsconfig.json", - isolatedModules: false, - }, - }, transform: { - "^.+\\.[jt]s?$": "ts-jest", + "^.+\\.[jt]s?$": [ + "ts-jest", + { + tsconfig: "tsconfig.json", + isolatedModules: false, + }, + ], }, testEnvironment: `node`, moduleFileExtensions: [`js`, `ts`], - testTimeout: 60000, + testTimeout: 100000, } diff --git a/packages/oas/medusa-oas-cli/package.json b/packages/oas/medusa-oas-cli/package.json index a4a95eb980..388b4bd003 100644 --- a/packages/oas/medusa-oas-cli/package.json +++ b/packages/oas/medusa-oas-cli/package.json @@ -21,9 +21,9 @@ "author": "Medusa", "license": "MIT", "devDependencies": { - "jest": "^25.5.4", + "jest": "^29.1.0", "js-yaml": "^4.1.0", - "ts-jest": "^25.5.1", + "ts-jest": "^29.1.0", "ts-node": "^10.9.1", "typescript": "4.9.5", "uuid": "^9.0.0" @@ -32,12 +32,14 @@ "prepare": "cross-env NODE_ENV=production yarn run build", "build": "tsc --build", "medusa-oas": "ts-node src/index.ts", - "test": "jest src" + "test": "NODE_OPTIONS='--unhandled-rejections=strict' jest src" }, "dependencies": { "@medusajs/medusa": "1.8.1", "@medusajs/openapi-typescript-codegen": "0.2.1", + "@readme/json-schema-ref-parser": "^1.2.0", "@readme/openapi-parser": "^2.4.0", + "@redocly/cli": "1.0.0-beta.123", "@types/lodash": "^4.14.191", "commander": "^10.0.0", "lodash": "^4.17.21", diff --git a/docs-util/redocly/plugins/decorators/circular-patch.js b/packages/oas/medusa-oas-cli/redocly/plugins/medusa/decorators/circular-patch.js similarity index 100% rename from docs-util/redocly/plugins/decorators/circular-patch.js rename to packages/oas/medusa-oas-cli/redocly/plugins/medusa/decorators/circular-patch.js diff --git a/docs-util/redocly/plugins/plugin.js b/packages/oas/medusa-oas-cli/redocly/plugins/medusa/index.js similarity index 90% rename from docs-util/redocly/plugins/plugin.js rename to packages/oas/medusa-oas-cli/redocly/plugins/medusa/index.js index 38ef77b32d..2b264e18d2 100644 --- a/docs-util/redocly/plugins/plugin.js +++ b/packages/oas/medusa-oas-cli/redocly/plugins/medusa/index.js @@ -1,6 +1,6 @@ const CircularPatch = require("./decorators/circular-patch") -const id = "plugin" +const id = "medusa" const decorators = { oas3: { diff --git a/docs-util/redocly/config.yaml b/packages/oas/medusa-oas-cli/redocly/redocly-config.yaml similarity index 97% rename from docs-util/redocly/config.yaml rename to packages/oas/medusa-oas-cli/redocly/redocly-config.yaml index aa8ad938ba..7b8ffadc3d 100644 --- a/docs-util/redocly/config.yaml +++ b/packages/oas/medusa-oas-cli/redocly/redocly-config.yaml @@ -1,11 +1,10 @@ plugins: - - "./plugins/plugin.js" + - "./plugins/medusa/index.js" # Allows to replace a $ref with `type: object` in order to avoid infinite loops # when Redocly attempts to render circular references. decorators: - plugin/circular-patch: - verbose: false + medusa/circular-patch: schemas: Address: - Customer @@ -143,7 +142,7 @@ theme: theme: colors: primary: - dart: "#242526" + dark: "#242526" sidebar: width: "250px" disableSearch: true diff --git a/packages/oas/medusa-oas-cli/src/__tests__/command-docs.test.ts b/packages/oas/medusa-oas-cli/src/__tests__/command-docs.test.ts new file mode 100644 index 0000000000..b075df6147 --- /dev/null +++ b/packages/oas/medusa-oas-cli/src/__tests__/command-docs.test.ts @@ -0,0 +1,376 @@ +import { exists, getTmpDirectory } from "../utils/fs-utils" +import { writeJson } from "../utils/json-utils" +import { OpenAPIObject } from "openapi3-ts" +import path from "path" +import { v4 as uid } from "uuid" +import { readYaml, writeYaml } from "../utils/yaml-utils" +import { mkdir, readdir } from "fs/promises" +import { + formatHintRecommendation, + getCircularPatchRecommendation, + getCircularReferences, +} from "../utils/circular-patch-utils" +import execa from "execa" + +const basePath = path.resolve(__dirname, `../../../`) + +export const runCLI = async (command: string, options: string[] = []) => { + const params = ["run", "medusa-oas", command, ...options] + try { + const { all: logs } = await execa("yarn", params, { + cwd: basePath, + all: true, + }) + } catch (err) { + throw new Error(err.message + err.all) + } +} + +export const getBaseOpenApi = (): OpenAPIObject => { + return { + openapi: "3.0.0", + info: { + title: "Test", + version: "1.0.0", + }, + paths: {}, + components: {}, + } +} + +describe("command docs", () => { + let tmpDir: string + let openApi: OpenAPIObject + + beforeAll(async () => { + tmpDir = await getTmpDirectory() + }) + + beforeEach(async () => { + openApi = getBaseOpenApi() + }) + + describe("basic usage", () => { + let srcFile: string + + beforeAll(async () => { + openApi = getBaseOpenApi() + openApi.components = { + schemas: { + Order: { + type: "object", + }, + }, + } + const outDir = path.resolve(tmpDir, uid()) + await mkdir(outDir, { recursive: true }) + srcFile = path.resolve(outDir, "store.oas.json") + await writeJson(srcFile, openApi) + }) + + it("should generate docs", async () => { + const outDir = path.resolve(tmpDir, uid()) + await runCLI("docs", ["--src-file", srcFile, "--out-dir", outDir]) + const generatedFilePath = path.resolve(outDir, "openapi.yaml") + const oas = (await readYaml(generatedFilePath)) as OpenAPIObject + const files = await readdir(outDir) + expect(oas.components?.schemas?.Order).toBeDefined() + expect(files.length).toBe(1) + }) + + it("should clean output directory", async () => { + const outDir = path.resolve(tmpDir, uid()) + await mkdir(outDir, { recursive: true }) + await writeJson(path.resolve(outDir, "test.json"), { foo: "bar" }) + await runCLI("docs", [ + "--src-file", + srcFile, + "--out-dir", + outDir, + "--clean", + ]) + const files = await readdir(outDir) + expect(files.includes("test.json")).toBeFalsy() + expect(files.length).toBe(1) + }) + + it("should not output any files", async () => { + const outDir = path.resolve(tmpDir, uid()) + await runCLI("docs", [ + "--src-file", + srcFile, + "--out-dir", + outDir, + "--dry-run", + ]) + const outDirExists = await exists(outDir) + expect(outDirExists).toBeFalsy() + }) + + it("should split output into multiple files and directories", async () => { + const outDir = path.resolve(tmpDir, uid()) + /** + * For split to output files, we need to not be in test mode + * See https://github.com/Redocly/redocly-cli/blob/v1.0.0-beta.125/packages/cli/src/utils.ts#L206-L215 + */ + const previousEnv = process.env.NODE_ENV + process.env.NODE_ENV = "development" + await runCLI("docs", [ + "--src-file", + srcFile, + "--out-dir", + outDir, + "--split", + "--clean", + ]) + process.env.NODE_ENV = previousEnv + const oasFileExists = await exists(path.resolve(outDir, "openapi.yaml")) + const outFileExists = await exists( + path.resolve(outDir, "components/schemas/Order.yaml") + ) + expect(oasFileExists).toBeTruthy() + expect(outFileExists).toBeTruthy() + }) + + it("should generate static HTML docs", async () => { + const outDir = path.resolve(tmpDir, uid()) + await runCLI("docs", [ + "--src-file", + srcFile, + "--out-dir", + outDir, + "--html", + ]) + const generatedFilePath = path.resolve(outDir, "index.html") + const htmlFileExists = await exists(generatedFilePath) + expect(htmlFileExists).toBeTruthy() + }) + }) + + describe("--config", () => { + let srcFile: string + let configFile: string + let configYamlFile: string + + beforeAll(async () => { + openApi = getBaseOpenApi() + openApi.components = { + schemas: { + Customer: { + type: "object", + properties: { + address: { + $ref: "#/components/schemas/Address", + }, + }, + }, + TestOrder: { + type: "object", + properties: { + address: { + $ref: "#/components/schemas/Address", + }, + }, + }, + Address: { + type: "object", + properties: { + /** + * We expect this circular reference to already be handled by + * our CLI's default redocly-config.yaml + */ + customer: { + $ref: "#/components/schemas/Customer", + }, + /** + * We expect this circular reference to not be handled. + */ + test_order: { + $ref: "#/components/schemas/TestOrder", + }, + }, + }, + }, + } + const config = { + decorators: { + "medusa/circular-patch": { + schemas: { + Address: ["TestOrder"], + }, + }, + }, + } + const outDir = path.resolve(tmpDir, uid()) + await mkdir(outDir, { recursive: true }) + srcFile = path.resolve(outDir, "store.oas.json") + await writeJson(srcFile, openApi) + configFile = path.resolve(outDir, "redocly-config.json") + await writeJson(configFile, config) + configYamlFile = path.resolve(outDir, "redocly-config.yaml") + await writeYaml(configYamlFile, config) + }) + + it("should fail with unhandled circular reference", async () => { + const outDir = path.resolve(tmpDir, uid()) + await expect( + runCLI("docs", [ + "--src-file", + srcFile, + "--out-dir", + outDir, + "--dry-run", + ]) + ).rejects.toThrow("Unhandled circular references") + }) + + it("should succeed with patched circular reference", async () => { + const outDir = path.resolve(tmpDir, uid()) + await expect( + runCLI("docs", [ + "--src-file", + srcFile, + "--out-dir", + outDir, + "--config", + configFile, + "--dry-run", + ]) + ).resolves.not.toThrow() + }) + + it("should succeed when config is of type yaml", async () => { + const outDir = path.resolve(tmpDir, uid()) + await expect( + runCLI("docs", [ + "--src-file", + srcFile, + "--out-dir", + outDir, + "--config", + configYamlFile, + "--dry-run", + ]) + ).resolves.not.toThrow() + }) + + it("should fail when config is not a file", async () => { + const outDir = path.resolve(tmpDir, uid()) + await expect( + runCLI("docs", [ + "--src-file", + srcFile, + "--out-dir", + outDir, + "--dry-run", + "--config", + outDir, + ]) + ).rejects.toThrow("--config must be a file") + }) + + it("should fail when config is not of supported file type", async () => { + const outDir = path.resolve(tmpDir, uid()) + await mkdir(outDir, { recursive: true }) + const tmpFile = path.resolve(outDir, "tmp.txt") + await writeJson(tmpFile, { foo: "bar" }) + await expect( + runCLI("docs", [ + "--src-file", + srcFile, + "--out-dir", + outDir, + "--dry-run", + "--config", + tmpFile, + ]) + ).rejects.toThrow("--config file must be of type .json or .yaml") + }) + }) + + describe("circular references", () => { + let srcFile: string + + beforeAll(async () => { + openApi = getBaseOpenApi() + openApi.components = { + schemas: { + Customer: { + type: "object", + properties: { + address: { + $ref: "#/components/schemas/Address", + }, + }, + }, + TestOrder: { + type: "object", + properties: { + address: { + $ref: "#/components/schemas/Address", + }, + }, + }, + Address: { + type: "object", + properties: { + customer: { + $ref: "#/components/schemas/Customer", + }, + test_order: { + $ref: "#/components/schemas/TestOrder", + }, + }, + }, + }, + } + const outDir = path.resolve(tmpDir, uid()) + await mkdir(outDir, { recursive: true }) + srcFile = path.resolve(outDir, "store.oas.json") + await writeJson(srcFile, openApi) + }) + + it("should find circular references", async () => { + const { circularRefs, oas } = await getCircularReferences(srcFile) + expect(circularRefs.length).toBe(2) + expect(circularRefs).toEqual( + expect.arrayContaining([ + "#/components/schemas/Address/properties/customer", + "#/components/schemas/TestOrder/properties/address", + ]) + ) + }) + + it("should recommend which schemas to patch to resolve circular references", async () => { + /** + * The recommendation is heavily influenced but the dereference operation + * from @readme/json-schema-ref-parser. It's not an exact science and the + * results may vary between versions. + */ + const { circularRefs, oas } = await getCircularReferences(srcFile) + const recommendation = getCircularPatchRecommendation(circularRefs, oas) + expect(recommendation).toEqual( + expect.objectContaining({ + Address: expect.arrayContaining(["Customer"]), + TestOrder: expect.arrayContaining(["Address"]), + }) + ) + }) + + it("should format hint", async () => { + const { circularRefs, oas } = await getCircularReferences(srcFile) + const recommendation = getCircularPatchRecommendation(circularRefs, oas) + const hint = formatHintRecommendation(recommendation) + expect(hint).toEqual( + expect.stringContaining(`decorators: + medusa/circular-patch: + schemas: + Address: + - Customer + TestOrder: + - Address +`) + ) + }) + }) +}) diff --git a/packages/oas/medusa-oas-cli/src/__tests__/command-oas.test.ts b/packages/oas/medusa-oas-cli/src/__tests__/command-oas.test.ts index 91e84dd133..224cce1ef5 100644 --- a/packages/oas/medusa-oas-cli/src/__tests__/command-oas.test.ts +++ b/packages/oas/medusa-oas-cli/src/__tests__/command-oas.test.ts @@ -1,26 +1,19 @@ -import execa from "execa" import fs from "fs/promises" -import * as yaml from "js-yaml" import { OpenAPIObject, SchemaObject } from "openapi3-ts" import { OperationObject } from "openapi3-ts/src/model/OpenApi" -import os from "os" import path from "path" import { v4 as uid } from "uuid" +import { getTmpDirectory } from "../utils/fs-utils" +import { readYaml } from "../utils/yaml-utils" +import { readJson } from "../utils/json-utils" +import execa from "execa" const medusaPackagePath = path.dirname( require.resolve("@medusajs/medusa/package.json") ) const basePath = path.resolve(__dirname, `../../`) -const getTmpDirectory = async () => { - /** - * RUNNER_TEMP: GitHub action, the path to a temporary directory on the runner. - */ - const tmpDir = process.env["RUNNER_TEMP"] ?? os.tmpdir() - return await fs.mkdtemp(tmpDir) -} - -const runCLI = async (command: string, options: string[] = []) => { +export const runCLI = async (command: string, options: string[] = []) => { const params = ["run", "medusa-oas", command, ...options] try { const { all: logs } = await execa("yarn", params, { @@ -28,25 +21,10 @@ const runCLI = async (command: string, options: string[] = []) => { all: true, }) } catch (err) { - console.error(err) - throw err + throw new Error(err.message + err.all) } } -const isFile = async (filePath): Promise => { - return (await fs.lstat(path.resolve(filePath))).isFile() -} - -const readJsonFile = async (filePath): Promise => { - const jsonString = await fs.readFile(filePath, "utf8") - return JSON.parse(jsonString) -} - -const readYamlFile = async (filePath): Promise => { - const yamlString = await fs.readFile(filePath, "utf8") - return yaml.load(yamlString) -} - const listOperations = (oas: OpenAPIObject): OperationObject[] => { const operations: OperationObject[] = [] for (const url in oas.paths) { @@ -91,7 +69,7 @@ describe("command oas", () => { const outDir = path.resolve(tmpDir, uid()) await runCLI("oas", ["--type", "admin", "--out-dir", outDir]) const generatedFilePath = path.resolve(outDir, "admin.oas.json") - oas = (await readJsonFile(generatedFilePath)) as OpenAPIObject + oas = (await readJson(generatedFilePath)) as OpenAPIObject }) it("generates oas with admin routes only", async () => { @@ -106,7 +84,7 @@ describe("command oas", () => { "oas", "admin.oas.base.yaml" ) - const oasBase = (await readYamlFile(yamlFilePath)) as OpenAPIObject + const oasBase = (await readYaml(yamlFilePath)) as OpenAPIObject expect(oas.info.title).toEqual(oasBase.info.title) }) }) @@ -118,7 +96,7 @@ describe("command oas", () => { const outDir = path.resolve(tmpDir, uid()) await runCLI("oas", ["--type", "store", "--out-dir", outDir]) const generatedFilePath = path.resolve(outDir, "store.oas.json") - oas = (await readJsonFile(generatedFilePath)) as OpenAPIObject + oas = (await readJson(generatedFilePath)) as OpenAPIObject }) it("generates oas with store routes only", async () => { @@ -133,7 +111,7 @@ describe("command oas", () => { "oas", "store.oas.base.yaml" ) - const oasBase = (await readYamlFile(yamlFilePath)) as OpenAPIObject + const oasBase = (await readYaml(yamlFilePath)) as OpenAPIObject expect(oas.info.title).toEqual(oasBase.info.title) }) }) @@ -145,7 +123,7 @@ describe("command oas", () => { const outDir = path.resolve(tmpDir, uid()) await runCLI("oas", ["--type", "combined", "--out-dir", outDir]) const generatedFilePath = path.resolve(outDir, "combined.oas.json") - oas = (await readJsonFile(generatedFilePath)) as OpenAPIObject + oas = (await readJson(generatedFilePath)) as OpenAPIObject }) it("generates oas with admin and store routes", async () => { @@ -160,7 +138,7 @@ describe("command oas", () => { "oas", "default.oas.base.yaml" ) - const oasBase = (await readYamlFile(yamlFilePath)) as OpenAPIObject + const oasBase = (await readYaml(yamlFilePath)) as OpenAPIObject expect(oas.info.title).toEqual(oasBase.info.title) }) @@ -244,7 +222,7 @@ describe("command oas", () => { additionalPath, ]) const generatedFilePath = path.resolve(outDir, "store.oas.json") - oas = (await readJsonFile(generatedFilePath)) as OpenAPIObject + oas = (await readJson(generatedFilePath)) as OpenAPIObject }) it("should add new path to existing paths", async () => { @@ -379,7 +357,7 @@ components: filePath, ]) const generatedFilePath = path.resolve(outDir, "store.oas.json") - oas = (await readJsonFile(generatedFilePath)) as OpenAPIObject + oas = (await readJson(generatedFilePath)) as OpenAPIObject }) it("should add new path to existing paths", async () => { diff --git a/packages/oas/medusa-oas-cli/src/command-client.ts b/packages/oas/medusa-oas-cli/src/command-client.ts index 9a196a30e3..00e699ac93 100644 --- a/packages/oas/medusa-oas-cli/src/command-client.ts +++ b/packages/oas/medusa-oas-cli/src/command-client.ts @@ -111,7 +111,7 @@ export async function execute(cliParams: OptionValues) { await generateClientSDK(oas, outDir, apiName, exportComponent, packageNames) console.log( - `🟢 Client generated - ${apiName} - ${exportComponent} - ${outDir}` + `⚫️ Client generated - ${apiName} - ${exportComponent} - ${outDir}` ) } diff --git a/packages/oas/medusa-oas-cli/src/command-docs.ts b/packages/oas/medusa-oas-cli/src/command-docs.ts new file mode 100644 index 0000000000..32178c7bec --- /dev/null +++ b/packages/oas/medusa-oas-cli/src/command-docs.ts @@ -0,0 +1,280 @@ +import { Command, Option, OptionValues } from "commander" +import fs, { mkdir } from "fs/promises" +import * as path from "path" +import execa from "execa" +import { jsonFileToYamlFile, readYaml, writeYaml } from "./utils/yaml-utils" +import { isArray, mergeWith } from "lodash" +import { readJson } from "./utils/json-utils" +import { getTmpDirectory, isFile } from "./utils/fs-utils" +import { + formatHintRecommendation, + getCircularPatchRecommendation, + getCircularReferences, +} from "./utils/circular-patch-utils" +import { previewDocs } from "@redocly/cli/lib/commands/preview-docs" + +/** + * Constants + */ +const basePath = path.resolve(__dirname, "../") + +const medusaPluginRelativePath = "./plugins/medusa/index.js" +const medusaPluginAbsolutePath = path.resolve( + basePath, + "redocly/plugins/medusa/index.js" +) +const configFileDefault = path.resolve(basePath, "redocly/redocly-config.yaml") + +/** + * CLI Command declaration + */ +export const commandName = "docs" +export const commandDescription = + "Sanitize OAS for use with Redocly's API documentation viewer." + +export const commandOptions: Option[] = [ + new Option( + "-s, --src-file ", + "Path to source OAS JSON file." + ).makeOptionMandatory(), + new Option( + "-o, --out-dir ", + "Destination directory to output the sanitized OAS files." + ).default(process.cwd()), + new Option( + "--config ", + "Configuration file to merge with default configuration before passing to Redocly's CLI." + ), + new Option("-D, --dry-run", "Do not output files."), + new Option( + "--clean", + "Delete destination directory content before generating documentation." + ), + new Option("--split", "Creates a multi-file structure output."), + new Option( + "--preview", + "Open a preview of the documentation. Does not output files." + ), + new Option( + "--html", + "Generate a static HTML using Redocly's build-docs command." + ), +] + +export function getCommand(): Command { + const command = new Command(commandName) + command.description(commandDescription) + for (const opt of commandOptions) { + command.addOption(opt) + } + command.action(async (options) => await execute(options)) + command.showHelpAfterError(true) + return command +} + +/** + * Main + */ +export async function execute(cliParams: OptionValues): Promise { + /** + * Process CLI options + */ + const shouldClean = !!cliParams.clean + const shouldSplit = !!cliParams.split + const shouldPreview = !!cliParams.preview + const shouldBuildHTML = !!cliParams.html + const dryRun = !!cliParams.dryRun + const srcFile = path.resolve(cliParams.srcFile) + const outDir = path.resolve(cliParams.outDir) + + const configFileCustom = cliParams.config + ? path.resolve(cliParams.config) + : undefined + if (configFileCustom) { + if (!(await isFile(configFileCustom))) { + throw new Error(`--config must be a file - ${configFileCustom}`) + } + if (![".json", ".yaml"].includes(path.extname(configFileCustom))) { + console.log(path.extname(configFileCustom)) + throw new Error( + `--config file must be of type .json or .yaml - ${configFileCustom}` + ) + } + } + + /** + * Command execution + */ + console.log(`🟣 Generating API documentation`) + + const tmpDir = await getTmpDirectory() + const configTmpFile = path.resolve(tmpDir, "redocly-config.yaml") + /** matches naming convention from `redocly split` */ + const finalOASFile = path.resolve(outDir, "openapi.yaml") + + await createTmpConfig(configFileDefault, configTmpFile) + if (configFileCustom) { + console.log( + `🔵 Merging configuration file - ${configFileCustom} > ${configTmpFile}` + ) + await mergeConfig(configTmpFile, configFileCustom, configTmpFile) + } + + if (!dryRun) { + if (shouldClean) { + console.log(`🟠 Cleaning output directory`) + await fs.rm(outDir, { recursive: true, force: true }) + } + await mkdir(outDir, { recursive: true }) + } + + const srcFileSanitized = path.resolve(tmpDir, "tmp.oas.json") + await sanitizeOAS(srcFile, srcFileSanitized, configTmpFile) + await circularReferenceCheck(srcFileSanitized) + + if (dryRun) { + console.log(`⚫️ Dry run - no files generated`) + return + } + if (shouldPreview) { + await preview(srcFileSanitized, configTmpFile) + return + } + if (shouldSplit) { + await generateReference(srcFileSanitized, outDir) + } else { + await jsonFileToYamlFile(srcFileSanitized, finalOASFile) + } + if (shouldBuildHTML) { + const outHTMLFile = path.resolve(outDir, "index.html") + await buildHTML(finalOASFile, outHTMLFile, configTmpFile) + } + console.log(`⚫️ API documentation generated - ${outDir}`) +} + +/** + * Methods + */ +type RedoclyConfig = { + apis?: Record + decorators?: Record + extends?: string[] + organization?: string + plugins?: string[] + preprocessors?: Record + region?: string + resolve?: Record + rules?: Record + theme?: Record +} + +const mergeConfig = async ( + configFileDefault: string, + configFileCustom: string, + configFileOut: string +): Promise => { + const configDefault = await readYaml(configFileDefault) + const configCustom = + path.extname(configFileCustom) === ".yaml" + ? await readYaml(configFileCustom) + : await readJson(configFileCustom) + + const config = mergeWith(configDefault, configCustom, (objValue, srcValue) => + isArray(objValue) ? objValue.concat(srcValue) : undefined + ) as RedoclyConfig + + await writeYaml(configFileOut, config) +} + +const createTmpConfig = async ( + configFileDefault: string, + configFileOut: string +): Promise => { + const config = (await readYaml(configFileDefault)) as RedoclyConfig + config.plugins = (config.plugins ?? []).filter( + (plugin) => plugin !== medusaPluginRelativePath + ) + config.plugins.push(medusaPluginAbsolutePath) + + await writeYaml(configFileOut, config) +} + +const sanitizeOAS = async ( + srcFile: string, + outFile: string, + configFile: string +): Promise => { + const { all: logs } = await execa( + "yarn", + [ + "redocly", + "bundle", + srcFile, + `--output=${outFile}`, + `--config=${configFile}`, + ], + { cwd: basePath, all: true } + ) + console.log(logs) +} + +const circularReferenceCheck = async (srcFile: string): Promise => { + const { circularRefs, oas } = await getCircularReferences(srcFile) + if (circularRefs.length) { + console.log(circularRefs) + let errorMessage = `🔴 Unhandled circular references - Please manually patch using --config ./redocly-config.yaml` + const recommendation = getCircularPatchRecommendation(circularRefs, oas) + if (Object.keys(recommendation).length) { + const hint = formatHintRecommendation(recommendation) + errorMessage += ` +Within redocly-config.yaml, try adding the following: +### +${hint} +### +` + } + throw new Error(errorMessage) + } + console.log(`🟢 All circular references are handled`) +} + +const generateReference = async ( + srcFile: string, + outDir: string +): Promise => { + const { all: logs } = await execa( + "yarn", + ["redocly", "split", srcFile, `--outDir=${outDir}`], + { cwd: basePath, all: true } + ) + console.log(logs) +} + +const preview = async (oasFile: string, configFile: string): Promise => { + await previewDocs({ + port: 8080, + host: "127.0.0.1", + api: oasFile, + config: configFile, + }) +} + +const buildHTML = async ( + srcFile: string, + outFile: string, + configFile: string +): Promise => { + const { all: logs } = await execa( + "yarn", + [ + "redocly", + "build-docs", + srcFile, + `--output=${outFile}`, + `--config=${configFile}`, + `--cdn=true`, + ], + { cwd: basePath, all: true } + ) + console.log(logs) +} diff --git a/packages/oas/medusa-oas-cli/src/command-oas.ts b/packages/oas/medusa-oas-cli/src/command-oas.ts index c3e67e44d6..56a36b0a46 100644 --- a/packages/oas/medusa-oas-cli/src/command-oas.ts +++ b/packages/oas/medusa-oas-cli/src/command-oas.ts @@ -9,6 +9,7 @@ import { mergeBaseIntoOAS, mergePathsAndSchemasIntoOAS, } from "./utils/merge-oas" +import { isFile } from "./utils/fs-utils" /** * Constants @@ -124,9 +125,11 @@ export async function execute(cliParams: OptionValues) { } await validateOAS(oas, apiType, force) - if (!dryRun) { - await exportOASToJSON(oas, apiType, outDir) + if (dryRun) { + console.log(`⚫️ Dry run - no files generated`) + return } + await exportOASToJSON(oas, apiType, outDir) } /** @@ -152,7 +155,7 @@ async function getOASFromCodebase( format: ".json", } ) - return await OpenAPIParser.parse(JSON.parse(gen)) + return (await OpenAPIParser.parse(JSON.parse(gen))) as OpenAPIObject } async function getOASFromPaths( @@ -168,7 +171,7 @@ async function getOASFromPaths( console.log(log) }, }) - return await OpenAPIParser.parse(JSON.parse(gen)) + return (await OpenAPIParser.parse(JSON.parse(gen))) as OpenAPIObject } async function validateOAS( @@ -195,7 +198,7 @@ async function exportOASToJSON( const json = JSON.stringify(oas, null, 2) const filePath = path.resolve(targetDir, `${apiType}.oas.json`) await writeFile(filePath, json) - console.log(`🔵 Exported OAS - ${apiType} - ${filePath}`) + console.log(`⚫️ Exported OAS - ${apiType} - ${filePath}`) } async function isDirectory(dirPath: string): Promise { @@ -206,12 +209,3 @@ async function isDirectory(dirPath: string): Promise { return false } } - -async function isFile(filePath: string): Promise { - try { - return (await lstat(path.resolve(filePath))).isFile() - } catch (err) { - console.log(err) - return false - } -} diff --git a/packages/oas/medusa-oas-cli/src/index.ts b/packages/oas/medusa-oas-cli/src/index.ts index 5baa5aa4d7..2903353837 100644 --- a/packages/oas/medusa-oas-cli/src/index.ts +++ b/packages/oas/medusa-oas-cli/src/index.ts @@ -3,6 +3,7 @@ import { Command } from "commander" import { getCommand as oasGetCommand } from "./command-oas" import { getCommand as clientGetCommand } from "./command-client" +import { getCommand as docsGetCommand } from "./command-docs" const run = async () => { const program = getBaseCommand() @@ -17,6 +18,11 @@ const run = async () => { */ program.addCommand(clientGetCommand()) + /** + * Alias to command-docs.ts + */ + program.addCommand(docsGetCommand()) + /** * Run CLI */ diff --git a/packages/oas/medusa-oas-cli/src/utils/circular-patch-utils.ts b/packages/oas/medusa-oas-cli/src/utils/circular-patch-utils.ts new file mode 100644 index 0000000000..5095f220fa --- /dev/null +++ b/packages/oas/medusa-oas-cli/src/utils/circular-patch-utils.ts @@ -0,0 +1,85 @@ +import { OpenAPIObject, SchemaObject } from "openapi3-ts" +import OpenAPIParser from "@readme/openapi-parser" +import { $Refs } from "@readme/json-schema-ref-parser" +import { jsonObjectToYamlString } from "./yaml-utils" + +export const getCircularReferences = async ( + srcFile: string +): Promise<{ circularRefs: string[]; oas: OpenAPIObject }> => { + const parser = new OpenAPIParser() + const oas = (await parser.validate(srcFile, { + dereference: { + circular: "ignore", + }, + })) as OpenAPIObject + if (parser.$refs.circular) { + const $refs = parser.$refs as $Refs + let circularRefs = $refs.circularRefs.map( + (ref) => ref.match(/#\/components\/schemas\/.*/)![0] + ) + circularRefs = [...new Set(circularRefs)] + circularRefs.sort() + return { circularRefs, oas } + } + return { circularRefs: [], oas } +} + +export const getCircularPatchRecommendation = ( + circularRefs: string[], + oas: OpenAPIObject +): Record => { + type circularReferenceMatch = { + schema: string + property: string + isArray: boolean + referencedSchema: string + } + const matches: circularReferenceMatch[] = circularRefs + .map((ref) => { + let match = + ref.match( + /(?:.*)(?:#\/components\/schemas\/)(.*)(?:\/properties\/?)(.*)/ + ) ?? [] + let schema = match[1] + let property = match[2] + let isArray = false + if (property.endsWith("/items")) { + property = property.replace("/items", "") + isArray = true + } + return { schema, property, isArray } + }) + .filter((match) => match.property !== "") + .map((match) => { + const baseSchema = oas.components!.schemas![match.schema] as SchemaObject + const propertySpec = match.isArray + ? (baseSchema.properties![match.property] as SchemaObject).items! + : baseSchema.properties![match.property] + const referencedSchema = propertySpec["$ref"].match( + /(?:#\/components\/schemas\/)(.*)/ + )![1] + return { + schema: match.schema, + property: match.property, + isArray: match.isArray, + referencedSchema, + } + }) + + const schemas = {} + for (const match of matches) { + if (!schemas.hasOwnProperty(match.schema)) { + schemas[match.schema] = [] + } + schemas[match.schema].push(match.referencedSchema) + } + return schemas +} + +export const formatHintRecommendation = ( + recommendation: Record +) => { + return jsonObjectToYamlString({ + decorators: { "medusa/circular-patch": { schemas: recommendation } }, + }) +} diff --git a/packages/oas/medusa-oas-cli/src/utils/fs-utils.ts b/packages/oas/medusa-oas-cli/src/utils/fs-utils.ts new file mode 100644 index 0000000000..65c866676c --- /dev/null +++ b/packages/oas/medusa-oas-cli/src/utils/fs-utils.ts @@ -0,0 +1,29 @@ +import { access, lstat, mkdtemp } from "fs/promises" +import path from "path" +import { tmpdir } from "os" + +export async function isFile(filePath: string): Promise { + try { + return (await lstat(path.resolve(filePath))).isFile() + } catch (err) { + console.log(err) + return false + } +} + +export async function exists(filePath: string): Promise { + try { + await access(path.resolve(filePath)) + return true + } catch (err) { + return false + } +} + +export const getTmpDirectory = async () => { + /** + * RUNNER_TEMP: GitHub action, the path to a temporary directory on the runner. + */ + const tmpDir = process.env["RUNNER_TEMP"] ?? tmpdir() + return await mkdtemp(tmpDir) +} diff --git a/packages/oas/medusa-oas-cli/src/utils/json-utils.ts b/packages/oas/medusa-oas-cli/src/utils/json-utils.ts new file mode 100644 index 0000000000..e33c208162 --- /dev/null +++ b/packages/oas/medusa-oas-cli/src/utils/json-utils.ts @@ -0,0 +1,14 @@ +import fs from "fs/promises" + +export const readJson = async (filePath: string): Promise => { + const jsonString = await fs.readFile(filePath, "utf8") + return JSON.parse(jsonString) +} + +export const writeJson = async ( + filePath: string, + jsonObject: unknown +): Promise => { + const jsonString = JSON.stringify(jsonObject) + await fs.writeFile(filePath, jsonString, "utf8") +} diff --git a/packages/oas/medusa-oas-cli/src/utils/yaml-utils.ts b/packages/oas/medusa-oas-cli/src/utils/yaml-utils.ts new file mode 100644 index 0000000000..b9d07bda2b --- /dev/null +++ b/packages/oas/medusa-oas-cli/src/utils/yaml-utils.ts @@ -0,0 +1,23 @@ +import fs from "fs/promises" +import * as yaml from "js-yaml" + +export const readYaml = async (filePath): Promise => { + const yamlString = await fs.readFile(filePath, "utf8") + return yaml.load(yamlString) +} + +export const writeYaml = async (filePath, jsonObject): Promise => { + const yamlString = yaml.dump(jsonObject) + await fs.writeFile(filePath, yamlString, "utf8") +} + +export const jsonObjectToYamlString = (jsonObject): string => { + return yaml.dump(jsonObject) +} + +export const jsonFileToYamlFile = async (inputJsonFile, outputYamlFile) => { + const jsonString = await fs.readFile(inputJsonFile, "utf8") + const jsonObject = JSON.parse(jsonString) + const yamlString = yaml.dump(jsonObject) + await fs.writeFile(outputYamlFile, yamlString, "utf8") +} diff --git a/packages/oas/oas-github-ci/package.json b/packages/oas/oas-github-ci/package.json index 585e905642..be88c20d22 100644 --- a/packages/oas/oas-github-ci/package.json +++ b/packages/oas/oas-github-ci/package.json @@ -1,6 +1,6 @@ { "name": "@medusajs/oas-github-ci", - "version": "1.0.2", + "version": "1.0.1", "description": "OAS Github CI", "main": "scripts/build-openapi.js", "files": [ @@ -16,15 +16,12 @@ "license": "MIT", "scripts": { "ci": "node scripts/build-openapi.js", - "preview:admin": "yarn redocly preview-docs ../../../docs/api/admin/openapi.yaml --config=../../../docs-util/redocly/config.yaml", - "preview:store": "yarn redocly preview-docs ../../../docs/api/store/openapi.yaml --config=../../../docs-util/redocly/config.yaml", + "preview:admin": "yarn medusa-oas docs --src-file ../../../docs/api/admin/openapi.yaml --preview", + "preview:store": "yarn medusa-oas docs --src-file ../../../docs/api/store/openapi.yaml --preview", "test": "jest --passWithNoTests" }, "dependencies": { "@medusajs/medusa-oas-cli": "0.2.1", - "@readme/openapi-parser": "^2.4.0", - "@redocly/cli": "1.0.0-beta.123", - "execa": "^5.1.1", - "js-yaml": "^4.1.0" + "execa": "^5.1.1" } } diff --git a/packages/oas/oas-github-ci/scripts/build-openapi.js b/packages/oas/oas-github-ci/scripts/build-openapi.js index f3f51e3214..6284d29b1c 100755 --- a/packages/oas/oas-github-ci/scripts/build-openapi.js +++ b/packages/oas/oas-github-ci/scripts/build-openapi.js @@ -4,37 +4,42 @@ const fs = require("fs/promises") const os = require("os") const path = require("path") const execa = require("execa") -const yaml = require("js-yaml") -const OpenAPIParser = require("@readme/openapi-parser") const isDryRun = process.argv.indexOf("--dry-run") !== -1 const basePath = path.resolve(__dirname, `../`) const repoRootPath = path.resolve(basePath, `../../../`) const docsApiPath = path.resolve(repoRootPath, "docs/api/") -const redoclyConfigPath = path.resolve( - repoRootPath, - "docs-util/redocly/config.yaml" -) const run = async () => { - const outputPath = isDryRun ? await getTmpDirectory() : docsApiPath - + const oasOutDir = isDryRun ? await getTmpDirectory() : docsApiPath for (const apiType of ["store", "admin"]) { - await generateOASSource(outputPath, apiType) - const inputJsonFile = path.resolve(outputPath, `${apiType}.oas.json`) - const outputYamlFile = path.resolve(outputPath, `${apiType}.oas.yaml`) - - await jsonFileToYamlFile(inputJsonFile, outputYamlFile) - await sanitizeOAS(outputYamlFile) - await circularReferenceCheck(outputYamlFile) - if (!isDryRun) { - await generateReference(outputYamlFile, apiType) - } + await generateOASSource(oasOutDir, apiType) + const oasSrcFile = path.resolve(oasOutDir, `${apiType}.oas.json`) + const docsOutDir = path.resolve(oasOutDir, apiType) + await generateDocs(oasSrcFile, docsOutDir, isDryRun) } } const generateOASSource = async (outDir, apiType) => { - const params = ["oas", `--type=${apiType}`, `--out-dir=${outDir}`] + const { all: logs } = await execa( + "medusa-oas", + ["oas", `--type=${apiType}`, `--out-dir=${outDir}`], + { cwd: basePath, all: true } + ) + console.log(logs) +} + +const generateDocs = async (srcFile, outDir, isDryRun) => { + const params = [ + "docs", + `--src-file=${srcFile}`, + `--out-dir=${outDir}`, + `--clean`, + `--split`, + ] + if (isDryRun) { + params.push("--dry-run") + } const { all: logs } = await execa("medusa-oas", params, { cwd: basePath, all: true, @@ -42,52 +47,6 @@ const generateOASSource = async (outDir, apiType) => { console.log(logs) } -const jsonFileToYamlFile = async (inputJsonFile, outputYamlFile) => { - const jsonString = await fs.readFile(inputJsonFile, "utf8") - const jsonObject = JSON.parse(jsonString) - const yamlString = yaml.dump(jsonObject) - await fs.writeFile(outputYamlFile, yamlString, "utf8") -} - -const sanitizeOAS = async (srcFile) => { - const { all: logs } = await execa( - "redocly", - ["bundle", srcFile, `--output=${srcFile}`, `--config=${redoclyConfigPath}`], - { cwd: basePath, all: true } - ) - console.log(logs) -} - -const circularReferenceCheck = async (srcFile) => { - const parser = new OpenAPIParser() - await parser.validate(srcFile, { - dereference: { - circular: "ignore", - }, - }) - if (parser.$refs.circular) { - const fileName = path.basename(srcFile) - const circularRefs = [...parser.$refs.circularRefs] - circularRefs.sort() - console.log(circularRefs) - throw new Error( - `🔴 Unhandled circular references - ${fileName} - Please patch in docs-util/redocly/config.yaml` - ) - } - console.log(`🟢 All circular references handled`) -} - -const generateReference = async (srcFile, apiType) => { - const outDir = path.resolve(docsApiPath, `${apiType}`) - await fs.rm(outDir, { recursive: true, force: true }) - const { all: logs } = await execa( - "redocly", - ["split", srcFile, `--outDir=${outDir}`], - { cwd: basePath, all: true } - ) - console.log(logs) -} - const getTmpDirectory = async () => { /** * RUNNER_TEMP: GitHub action, the path to a temporary directory on the runner. diff --git a/yarn.lock b/yarn.lock index e268e1561a..efdef0c284 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4132,6 +4132,20 @@ __metadata: languageName: node linkType: hard +"@jest/console@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/console@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + jest-message-util: ^29.5.0 + jest-util: ^29.5.0 + slash: ^3.0.0 + checksum: 59dfbdb6c3c15652f8d7267071f24d6335afbed0b1cf71aed70b6ce8deb1d86e7f4aadb978f639435650107fd22476b59e63a3d3a9ac99b1aca739b795a54410 + languageName: node + linkType: hard + "@jest/core@npm:^25.5.4": version: 25.5.4 resolution: "@jest/core@npm:25.5.4" @@ -4286,6 +4300,47 @@ __metadata: languageName: node linkType: hard +"@jest/core@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/core@npm:29.5.0" + dependencies: + "@jest/console": ^29.5.0 + "@jest/reporters": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + ansi-escapes: ^4.2.1 + chalk: ^4.0.0 + ci-info: ^3.2.0 + exit: ^0.1.2 + graceful-fs: ^4.2.9 + jest-changed-files: ^29.5.0 + jest-config: ^29.5.0 + jest-haste-map: ^29.5.0 + jest-message-util: ^29.5.0 + jest-regex-util: ^29.4.3 + jest-resolve: ^29.5.0 + jest-resolve-dependencies: ^29.5.0 + jest-runner: ^29.5.0 + jest-runtime: ^29.5.0 + jest-snapshot: ^29.5.0 + jest-util: ^29.5.0 + jest-validate: ^29.5.0 + jest-watcher: ^29.5.0 + micromatch: ^4.0.4 + pretty-format: ^29.5.0 + slash: ^3.0.0 + strip-ansi: ^6.0.0 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + checksum: e4b3e0de48614b2c339083b9159f00a024839984bd89b9afa4cfff4c38f6ce485c2009f2efa1c1e3bb3b87386288bc15798c6aebb7937d7820e8048d75461a4d + languageName: node + linkType: hard + "@jest/environment@npm:^25.5.0": version: 25.5.0 resolution: "@jest/environment@npm:25.5.0" @@ -4333,6 +4388,18 @@ __metadata: languageName: node linkType: hard +"@jest/environment@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/environment@npm:29.5.0" + dependencies: + "@jest/fake-timers": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + jest-mock: ^29.5.0 + checksum: 1fbe63cbfb9c3f6c9fc9d8f6917a5aceee1828d589569bbffcf5fb4bb56bc021dc3a6f239cde3099144767c97763ae134904ee522f236cd8c0d071bd7f9ef63b + languageName: node + linkType: hard + "@jest/expect-utils@npm:^29.4.1": version: 29.4.1 resolution: "@jest/expect-utils@npm:29.4.1" @@ -4351,6 +4418,15 @@ __metadata: languageName: node linkType: hard +"@jest/expect-utils@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/expect-utils@npm:29.5.0" + dependencies: + jest-get-type: ^29.4.3 + checksum: e7f44de651b5ef71c6e1b7a0350a704258167c20b6e8165b3100346d5c7f8eb4cd2c229ea2c048e9161666d1c086fbbc422f111f3b77da3fb89a99d52d4b3690 + languageName: node + linkType: hard + "@jest/expect@npm:^29.4.1": version: 29.4.1 resolution: "@jest/expect@npm:29.4.1" @@ -4361,6 +4437,16 @@ __metadata: languageName: node linkType: hard +"@jest/expect@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/expect@npm:29.5.0" + dependencies: + expect: ^29.5.0 + jest-snapshot: ^29.5.0 + checksum: 447e7450af8ba61ac34d8a2ca11c56c62f6f0fb33ff13130f11a1ec9526a08d756ee72da622316a2c52ecfe726fe14432bdfb46e45aff5676f8d1a8efc8d201c + languageName: node + linkType: hard + "@jest/fake-timers@npm:^25.5.0": version: 25.5.0 resolution: "@jest/fake-timers@npm:25.5.0" @@ -4416,6 +4502,20 @@ __metadata: languageName: node linkType: hard +"@jest/fake-timers@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/fake-timers@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@sinonjs/fake-timers": ^10.0.2 + "@types/node": "*" + jest-message-util: ^29.5.0 + jest-mock: ^29.5.0 + jest-util: ^29.5.0 + checksum: dbf52fd302bf6b3d7ec49499f12835b7d7d4069d61adc62dac233021eba61186bbad3add1ceb3225a23a8745dd04fa0dcc2c38d350ecb0f26eec63f2cf5e6aff + languageName: node + linkType: hard + "@jest/globals@npm:^25.5.2": version: 25.5.2 resolution: "@jest/globals@npm:25.5.2" @@ -4461,6 +4561,18 @@ __metadata: languageName: node linkType: hard +"@jest/globals@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/globals@npm:29.5.0" + dependencies: + "@jest/environment": ^29.5.0 + "@jest/expect": ^29.5.0 + "@jest/types": ^29.5.0 + jest-mock: ^29.5.0 + checksum: 0c25f07d8125e45cf3c21442e625f6a636eaf7f4cf1cf3f9f66bae059aeb31d3dc61dfff9479eb861a5089dca34c95e231ad88b8925bee42387abecbfe5ecbc2 + languageName: node + linkType: hard + "@jest/reporters@npm:^25.5.1": version: 25.5.1 resolution: "@jest/reporters@npm:25.5.1" @@ -4608,6 +4720,43 @@ __metadata: languageName: node linkType: hard +"@jest/reporters@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/reporters@npm:29.5.0" + dependencies: + "@bcoe/v8-coverage": ^0.2.3 + "@jest/console": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@jridgewell/trace-mapping": ^0.3.15 + "@types/node": "*" + chalk: ^4.0.0 + collect-v8-coverage: ^1.0.0 + exit: ^0.1.2 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + istanbul-lib-coverage: ^3.0.0 + istanbul-lib-instrument: ^5.1.0 + istanbul-lib-report: ^3.0.0 + istanbul-lib-source-maps: ^4.0.0 + istanbul-reports: ^3.1.3 + jest-message-util: ^29.5.0 + jest-util: ^29.5.0 + jest-worker: ^29.5.0 + slash: ^3.0.0 + string-length: ^4.0.1 + strip-ansi: ^6.0.0 + v8-to-istanbul: ^9.0.1 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + checksum: 72b771a7749ac2eb9b671f2a886dc98cbe914dfa1a4266854b040e4cc563bf9f5db02b8ff8654b7bfbc3b28caa6d48ca0dde9707454ea4f79d77bd13b6357929 + languageName: node + linkType: hard + "@jest/schemas@npm:^29.4.0": version: 29.4.0 resolution: "@jest/schemas@npm:29.4.0" @@ -4670,6 +4819,17 @@ __metadata: languageName: node linkType: hard +"@jest/source-map@npm:^29.4.3": + version: 29.4.3 + resolution: "@jest/source-map@npm:29.4.3" + dependencies: + "@jridgewell/trace-mapping": ^0.3.15 + callsites: ^3.0.0 + graceful-fs: ^4.2.9 + checksum: 353f9989dcb416e8a2559ad2831b4b3e8446a9f8259782cec97f89903b5c00baa76ea3e23a3f1c83c1ccb3999a9e318b8c6a4bab29e4b66a4abdbb760e445a50 + languageName: node + linkType: hard + "@jest/test-result@npm:^25.5.0": version: 25.5.0 resolution: "@jest/test-result@npm:25.5.0" @@ -4718,6 +4878,18 @@ __metadata: languageName: node linkType: hard +"@jest/test-result@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/test-result@npm:29.5.0" + dependencies: + "@jest/console": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/istanbul-lib-coverage": ^2.0.0 + collect-v8-coverage: ^1.0.0 + checksum: 5d637c9935ea0438b2a7c106d48756967e5a96fa4426a9b16ea2a3e73e1538eabd10fd4faa8eb46aa4fee710a165e0fd2ce0603dacde5e8a1bba541100854b1d + languageName: node + linkType: hard + "@jest/test-sequencer@npm:^25.5.4": version: 25.5.4 resolution: "@jest/test-sequencer@npm:25.5.4" @@ -4768,6 +4940,18 @@ __metadata: languageName: node linkType: hard +"@jest/test-sequencer@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/test-sequencer@npm:29.5.0" + dependencies: + "@jest/test-result": ^29.5.0 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.5.0 + slash: ^3.0.0 + checksum: 6fb7549a5dbe2da6817eb853134f76cf2b320b283900c5e63c997ecfadc616379372a49ac8c0f4ffdb9616eed4a5908c74cb7a560a395a6e1dc0d072b865657b + languageName: node + linkType: hard + "@jest/transform@npm:^25.5.1": version: 25.5.1 resolution: "@jest/transform@npm:25.5.1" @@ -4861,6 +5045,29 @@ __metadata: languageName: node linkType: hard +"@jest/transform@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/transform@npm:29.5.0" + dependencies: + "@babel/core": ^7.11.6 + "@jest/types": ^29.5.0 + "@jridgewell/trace-mapping": ^0.3.15 + babel-plugin-istanbul: ^6.1.1 + chalk: ^4.0.0 + convert-source-map: ^2.0.0 + fast-json-stable-stringify: ^2.1.0 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.5.0 + jest-regex-util: ^29.4.3 + jest-util: ^29.5.0 + micromatch: ^4.0.4 + pirates: ^4.0.4 + slash: ^3.0.0 + write-file-atomic: ^4.0.2 + checksum: 113598311d84ec7e4a4aadd340e332bbfbbd66e20eabea8b2f084b80cf97c1bc9e1ff90278c4f04b227afa95e3386d702363715f9923062c370c042c31911d94 + languageName: node + linkType: hard + "@jest/types@npm:^25.5.0": version: 25.5.0 resolution: "@jest/types@npm:25.5.0" @@ -4927,6 +5134,20 @@ __metadata: languageName: node linkType: hard +"@jest/types@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/types@npm:29.5.0" + dependencies: + "@jest/schemas": ^29.4.3 + "@types/istanbul-lib-coverage": ^2.0.0 + "@types/istanbul-reports": ^3.0.0 + "@types/node": "*" + "@types/yargs": ^17.0.8 + chalk: ^4.0.0 + checksum: f1cccd2e9b00a985bfdac03517f906cdf7a481be3606c335f8ec08a7272b7cf700b23484ce323a912b374defb90d3ab88c643cf2a2f47635c1c4feacfa1c1b2d + languageName: node + linkType: hard + "@jimp/bmp@npm:^0.16.1": version: 0.16.1 resolution: "@jimp/bmp@npm:0.16.1" @@ -5864,15 +6085,17 @@ __metadata: dependencies: "@medusajs/medusa": 1.8.1 "@medusajs/openapi-typescript-codegen": 0.2.1 + "@readme/json-schema-ref-parser": ^1.2.0 "@readme/openapi-parser": ^2.4.0 + "@redocly/cli": 1.0.0-beta.123 "@types/lodash": ^4.14.191 commander: ^10.0.0 - jest: ^25.5.4 + jest: ^29.1.0 js-yaml: ^4.1.0 lodash: ^4.17.21 openapi3-ts: ^3.1.2 swagger-inline: ^6.1.0 - ts-jest: ^25.5.1 + ts-jest: ^29.1.0 ts-node: ^10.9.1 typescript: 4.9.5 uuid: ^9.0.0 @@ -5973,10 +6196,7 @@ __metadata: resolution: "@medusajs/oas-github-ci@workspace:packages/oas/oas-github-ci" dependencies: "@medusajs/medusa-oas-cli": 0.2.1 - "@readme/openapi-parser": ^2.4.0 - "@redocly/cli": 1.0.0-beta.123 execa: ^5.1.1 - js-yaml: ^4.1.0 languageName: unknown linkType: soft @@ -13983,6 +14203,23 @@ __metadata: languageName: node linkType: hard +"babel-jest@npm:^29.5.0": + version: 29.5.0 + resolution: "babel-jest@npm:29.5.0" + dependencies: + "@jest/transform": ^29.5.0 + "@types/babel__core": ^7.1.14 + babel-plugin-istanbul: ^6.1.1 + babel-preset-jest: ^29.5.0 + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + slash: ^3.0.0 + peerDependencies: + "@babel/core": ^7.8.0 + checksum: 1114d3935e0f62b72e155ac79916214c078e798561be3b03d12ddd862f2849becc8516f89046719161ec457bded35d2e1fd7ddfb207a6169dd18bbb2a67ee987 + languageName: node + linkType: hard + "babel-jsx-utils@npm:^1.1.0": version: 1.1.0 resolution: "babel-jsx-utils@npm:1.1.0" @@ -14109,6 +14346,18 @@ __metadata: languageName: node linkType: hard +"babel-plugin-jest-hoist@npm:^29.5.0": + version: 29.5.0 + resolution: "babel-plugin-jest-hoist@npm:29.5.0" + dependencies: + "@babel/template": ^7.3.3 + "@babel/types": ^7.3.3 + "@types/babel__core": ^7.1.14 + "@types/babel__traverse": ^7.0.6 + checksum: 385547c4d81647848dc3e86fecf4381032be99ed97d87aee78d422631f651042600371ee31e37ec9bb6f4a0a4f296b3b5798d69c410626ea94eae76d9c64da63 + languageName: node + linkType: hard + "babel-plugin-lodash@npm:^3.3.4": version: 3.3.4 resolution: "babel-plugin-lodash@npm:3.3.4" @@ -14444,6 +14693,18 @@ __metadata: languageName: node linkType: hard +"babel-preset-jest@npm:^29.5.0": + version: 29.5.0 + resolution: "babel-preset-jest@npm:29.5.0" + dependencies: + babel-plugin-jest-hoist: ^29.5.0 + babel-preset-current-node-syntax: ^1.0.0 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 752b8682c8cf55bca46d870003f4ce43a4ba0fcaa1138ff7f0e02340628e221810b0c2c3e77a7d5070168dc163eb11907f6c9256f187242abe0f14219d1f6b12 + languageName: node + linkType: hard + "babel-preset-medusa-package@*, babel-preset-medusa-package@^1.0.0, babel-preset-medusa-package@^1.1.19, babel-preset-medusa-package@workspace:packages/babel-preset-medusa-package": version: 0.0.0-use.local resolution: "babel-preset-medusa-package@workspace:packages/babel-preset-medusa-package" @@ -19969,6 +20230,19 @@ __metadata: languageName: node linkType: hard +"expect@npm:^29.5.0": + version: 29.5.0 + resolution: "expect@npm:29.5.0" + dependencies: + "@jest/expect-utils": ^29.5.0 + jest-get-type: ^29.4.3 + jest-matcher-utils: ^29.5.0 + jest-message-util: ^29.5.0 + jest-util: ^29.5.0 + checksum: 3c9382967217ad1453e9271e0da3f83c4aeb12272968007b90fc5873340e7fb64bf4852e1522bdf27556623d031ce62f82aaac09e485a15c6d0589d50999422d + languageName: node + linkType: hard + "expected-node-version@npm:^1.0.0": version: 1.0.2 resolution: "expected-node-version@npm:1.0.2" @@ -24553,6 +24827,16 @@ __metadata: languageName: node linkType: hard +"jest-changed-files@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-changed-files@npm:29.5.0" + dependencies: + execa: ^5.0.0 + p-limit: ^3.1.0 + checksum: 96334c78507a13c0f11f1360d893ade78fba7fd169825ca4acf7565156ceddd89b952be81c00378fa87ab642d3f44902c34a20f21b561e985e79f6e81fa7e9a8 + languageName: node + linkType: hard + "jest-circus@npm:^27.5.1": version: 27.5.1 resolution: "jest-circus@npm:27.5.1" @@ -24607,6 +24891,34 @@ __metadata: languageName: node linkType: hard +"jest-circus@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-circus@npm:29.5.0" + dependencies: + "@jest/environment": ^29.5.0 + "@jest/expect": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + co: ^4.6.0 + dedent: ^0.7.0 + is-generator-fn: ^2.0.0 + jest-each: ^29.5.0 + jest-matcher-utils: ^29.5.0 + jest-message-util: ^29.5.0 + jest-runtime: ^29.5.0 + jest-snapshot: ^29.5.0 + jest-util: ^29.5.0 + p-limit: ^3.1.0 + pretty-format: ^29.5.0 + pure-rand: ^6.0.0 + slash: ^3.0.0 + stack-utils: ^2.0.3 + checksum: 77f77b826941f67e9794e185072ee612cbddf53a1cfbf736de86176b7dc54e54aef151cf31b492adaef221f550924fd60dbaa01c9b939c3a4bfb46d8392c60a8 + languageName: node + linkType: hard + "jest-cli@npm:^25.5.4": version: 25.5.4 resolution: "jest-cli@npm:25.5.4" @@ -24708,6 +25020,33 @@ __metadata: languageName: node linkType: hard +"jest-cli@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-cli@npm:29.5.0" + dependencies: + "@jest/core": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/types": ^29.5.0 + chalk: ^4.0.0 + exit: ^0.1.2 + graceful-fs: ^4.2.9 + import-local: ^3.0.2 + jest-config: ^29.5.0 + jest-util: ^29.5.0 + jest-validate: ^29.5.0 + prompts: ^2.0.1 + yargs: ^17.3.1 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + bin: + jest: bin/jest.js + checksum: d63df7e329760bc036d11980883399de86b41a7fa93bbc2e79feef28284b096dec40afc21796504555ccbf32806bfc78cf64a63eac9093bb4f036b282b409863 + languageName: node + linkType: hard + "jest-config@npm:^25.5.4": version: 25.5.4 resolution: "jest-config@npm:25.5.4" @@ -24841,6 +25180,44 @@ __metadata: languageName: node linkType: hard +"jest-config@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-config@npm:29.5.0" + dependencies: + "@babel/core": ^7.11.6 + "@jest/test-sequencer": ^29.5.0 + "@jest/types": ^29.5.0 + babel-jest: ^29.5.0 + chalk: ^4.0.0 + ci-info: ^3.2.0 + deepmerge: ^4.2.2 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + jest-circus: ^29.5.0 + jest-environment-node: ^29.5.0 + jest-get-type: ^29.4.3 + jest-regex-util: ^29.4.3 + jest-resolve: ^29.5.0 + jest-runner: ^29.5.0 + jest-util: ^29.5.0 + jest-validate: ^29.5.0 + micromatch: ^4.0.4 + parse-json: ^5.2.0 + pretty-format: ^29.5.0 + slash: ^3.0.0 + strip-json-comments: ^3.1.1 + peerDependencies: + "@types/node": "*" + ts-node: ">=9.0.0" + peerDependenciesMeta: + "@types/node": + optional: true + ts-node: + optional: true + checksum: 01780eb66815e3d31d237aab5d7611ea59e0cdf159cbab2a7c682cb08bde6d053c17a528547440fb1b0294c26ebfd5b54ad35d8c9439f6fae76960ee0bc90197 + languageName: node + linkType: hard + "jest-diff@npm:^25.5.0": version: 25.5.0 resolution: "jest-diff@npm:25.5.0" @@ -24901,6 +25278,18 @@ __metadata: languageName: node linkType: hard +"jest-diff@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-diff@npm:29.5.0" + dependencies: + chalk: ^4.0.0 + diff-sequences: ^29.4.3 + jest-get-type: ^29.4.3 + pretty-format: ^29.5.0 + checksum: 00fda597fa6ee22774453c3cd35c2210bd7f749cf48ad7a41c13b898b2943c9c047842720eb928cdb949b9de87204d8d8987bf12aefdb2f0504f5f4112cab5b0 + languageName: node + linkType: hard + "jest-docblock@npm:^25.3.0": version: 25.3.0 resolution: "jest-docblock@npm:25.3.0" @@ -24937,6 +25326,15 @@ __metadata: languageName: node linkType: hard +"jest-docblock@npm:^29.4.3": + version: 29.4.3 + resolution: "jest-docblock@npm:29.4.3" + dependencies: + detect-newline: ^3.0.0 + checksum: 25cdea8fe77ff09d958abd347e26dcd8766ca69d9935bc626a89d694c91d33be06d4c088b02e4b3f143f532f726a10dff0bfe1e2387a0972a95addf5d64ed407 + languageName: node + linkType: hard + "jest-each@npm:^25.5.0": version: 25.5.0 resolution: "jest-each@npm:25.5.0" @@ -24989,6 +25387,19 @@ __metadata: languageName: node linkType: hard +"jest-each@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-each@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + chalk: ^4.0.0 + jest-get-type: ^29.4.3 + jest-util: ^29.5.0 + pretty-format: ^29.5.0 + checksum: 214f6b5adfc0d6a3e837769018b7a7b69f41e99aac939fe4730bcca23f69e3566ed23706f95a396b20e63e6b9f90990053fc3c1662808036d4f41e4d6d32641d + languageName: node + linkType: hard + "jest-environment-jsdom@npm:^25.5.0": version: 25.5.0 resolution: "jest-environment-jsdom@npm:25.5.0" @@ -25110,6 +25521,20 @@ __metadata: languageName: node linkType: hard +"jest-environment-node@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-environment-node@npm:29.5.0" + dependencies: + "@jest/environment": ^29.5.0 + "@jest/fake-timers": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + jest-mock: ^29.5.0 + jest-util: ^29.5.0 + checksum: 2e636a095ff9a9e0aa20fda5b4c06eebed8f3ba2411062bdf724b114eedafd49b880167998af9f77aa8aa68231621aebe3998389d73433e9553ea5735cad1e14 + languageName: node + linkType: hard + "jest-get-type@npm:^25.2.6": version: 25.2.6 resolution: "jest-get-type@npm:25.2.6" @@ -25241,6 +25666,29 @@ __metadata: languageName: node linkType: hard +"jest-haste-map@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-haste-map@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@types/graceful-fs": ^4.1.3 + "@types/node": "*" + anymatch: ^3.0.3 + fb-watchman: ^2.0.0 + fsevents: ^2.3.2 + graceful-fs: ^4.2.9 + jest-regex-util: ^29.4.3 + jest-util: ^29.5.0 + jest-worker: ^29.5.0 + micromatch: ^4.0.4 + walker: ^1.0.8 + dependenciesMeta: + fsevents: + optional: true + checksum: 162edfa185478db9ebe7dff73f3475ef2c205d94fa2b0fc3b41aba4fc29bab274d4a76ca41ca20ea7d9d6ed2b0d8519e298cfffbf5cad6631412d8961c190612 + languageName: node + linkType: hard + "jest-jasmine2@npm:^25.5.4": version: 25.5.4 resolution: "jest-jasmine2@npm:25.5.4" @@ -25357,6 +25805,16 @@ __metadata: languageName: node linkType: hard +"jest-leak-detector@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-leak-detector@npm:29.5.0" + dependencies: + jest-get-type: ^29.4.3 + pretty-format: ^29.5.0 + checksum: d7db5d4a7cb676fc151f533d6887f3d6bbb4e35346346cbed0b5583c296b13af2d3c8434b30f62b0eb9c711718c7f4bd48496c47af3a20320ee162e33d64aaf2 + languageName: node + linkType: hard + "jest-matcher-utils@npm:^25.5.0": version: 25.5.0 resolution: "jest-matcher-utils@npm:25.5.0" @@ -25417,6 +25875,18 @@ __metadata: languageName: node linkType: hard +"jest-matcher-utils@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-matcher-utils@npm:29.5.0" + dependencies: + chalk: ^4.0.0 + jest-diff: ^29.5.0 + jest-get-type: ^29.4.3 + pretty-format: ^29.5.0 + checksum: 0a3ae95ef5c5c4ac2b2c503c2f57e173fa82725722e1fadcd902fd801afe17d9d36e9366820959465f553627bf1e481a0e4a540125f3b4371eec674b3557f7f3 + languageName: node + linkType: hard + "jest-message-util@npm:^25.5.0": version: 25.5.0 resolution: "jest-message-util@npm:25.5.0" @@ -25501,6 +25971,23 @@ __metadata: languageName: node linkType: hard +"jest-message-util@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-message-util@npm:29.5.0" + dependencies: + "@babel/code-frame": ^7.12.13 + "@jest/types": ^29.5.0 + "@types/stack-utils": ^2.0.0 + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + micromatch: ^4.0.4 + pretty-format: ^29.5.0 + slash: ^3.0.0 + stack-utils: ^2.0.3 + checksum: 706e89cacc89c090af584f4687c4e7f0616706481e468ec7c88270e07ae7458a829e477b7b3dff56b75d801f799d65eb2c28d6453c25dd02bea0fd98f0809dbb + languageName: node + linkType: hard + "jest-mock@npm:^25.5.0": version: 25.5.0 resolution: "jest-mock@npm:25.5.0" @@ -25541,6 +26028,17 @@ __metadata: languageName: node linkType: hard +"jest-mock@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-mock@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@types/node": "*" + jest-util: ^29.5.0 + checksum: c5b71d397d6acd44d99cd48dad8ca76334fc5a27e120da72d264d7527a9efc7c6fc431d79de64d0b73aa0ab26a2d0712498e323d42b9e03bee05e983b0d2035c + languageName: node + linkType: hard + "jest-pnp-resolver@npm:^1.2.1, jest-pnp-resolver@npm:^1.2.2": version: 1.2.2 resolution: "jest-pnp-resolver@npm:1.2.2" @@ -25581,6 +26079,13 @@ __metadata: languageName: node linkType: hard +"jest-regex-util@npm:^29.4.3": + version: 29.4.3 + resolution: "jest-regex-util@npm:29.4.3" + checksum: a7a4508bda47c5177e7337fb6fb22e9adab414ba141f224c9992c86973da1ccf5c69040e63636090ad26ef3a123d28bec950fa99496c157444b4f847e5e5a670 + languageName: node + linkType: hard + "jest-resolve-dependencies@npm:^25.5.4": version: 25.5.4 resolution: "jest-resolve-dependencies@npm:25.5.4" @@ -25624,6 +26129,16 @@ __metadata: languageName: node linkType: hard +"jest-resolve-dependencies@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-resolve-dependencies@npm:29.5.0" + dependencies: + jest-regex-util: ^29.4.3 + jest-snapshot: ^29.5.0 + checksum: fbe513b7d905c4a70be17fd1cb4bd83da1e82cceb47ed7ceababbe11c75f1d0c18eadeb3f4ebb6997ba979f35fa18dfd02e1d57eb556675e47b35675fde0aac7 + languageName: node + linkType: hard + "jest-resolve@npm:^25.5.1": version: 25.5.1 resolution: "jest-resolve@npm:25.5.1" @@ -25692,6 +26207,23 @@ __metadata: languageName: node linkType: hard +"jest-resolve@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-resolve@npm:29.5.0" + dependencies: + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.5.0 + jest-pnp-resolver: ^1.2.2 + jest-util: ^29.5.0 + jest-validate: ^29.5.0 + resolve: ^1.20.0 + resolve.exports: ^2.0.0 + slash: ^3.0.0 + checksum: e7ea3b1cf865a7e63ad297d0f43a093dde145f9ca72dc8e75b6c7eb3af60fe78e4f7d024fd92fa280419a4ca038d42a9268d4d5d512958d11347e680daca1f12 + languageName: node + linkType: hard + "jest-runner@npm:^25.5.4": version: 25.5.4 resolution: "jest-runner@npm:25.5.4" @@ -25805,6 +26337,35 @@ __metadata: languageName: node linkType: hard +"jest-runner@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-runner@npm:29.5.0" + dependencies: + "@jest/console": ^29.5.0 + "@jest/environment": ^29.5.0 + "@jest/test-result": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + emittery: ^0.13.1 + graceful-fs: ^4.2.9 + jest-docblock: ^29.4.3 + jest-environment-node: ^29.5.0 + jest-haste-map: ^29.5.0 + jest-leak-detector: ^29.5.0 + jest-message-util: ^29.5.0 + jest-resolve: ^29.5.0 + jest-runtime: ^29.5.0 + jest-util: ^29.5.0 + jest-watcher: ^29.5.0 + jest-worker: ^29.5.0 + p-limit: ^3.1.0 + source-map-support: 0.5.13 + checksum: 96f47976b9bcc0554455c200d02ebc1547b9a7749b05353c0d55aff535509032c0c12ea25ccc294350f62c14665dbc1e00b15e0d1c52207edfb807e4fec4a36a + languageName: node + linkType: hard + "jest-runtime@npm:^25.5.4": version: 25.5.4 resolution: "jest-runtime@npm:25.5.4" @@ -25939,6 +26500,36 @@ __metadata: languageName: node linkType: hard +"jest-runtime@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-runtime@npm:29.5.0" + dependencies: + "@jest/environment": ^29.5.0 + "@jest/fake-timers": ^29.5.0 + "@jest/globals": ^29.5.0 + "@jest/source-map": ^29.4.3 + "@jest/test-result": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + cjs-module-lexer: ^1.0.0 + collect-v8-coverage: ^1.0.0 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + jest-haste-map: ^29.5.0 + jest-message-util: ^29.5.0 + jest-mock: ^29.5.0 + jest-regex-util: ^29.4.3 + jest-resolve: ^29.5.0 + jest-snapshot: ^29.5.0 + jest-util: ^29.5.0 + slash: ^3.0.0 + strip-bom: ^4.0.0 + checksum: 9b5c0a97e1f24945059695e056188041730a3f1dc5924153e323eb7429244e10e7cc877b13d057869d6621c460deae11b77a2a2e9ab56e22b56864a3e44c4448 + languageName: node + linkType: hard + "jest-serializer@npm:^25.5.0": version: 25.5.0 resolution: "jest-serializer@npm:25.5.0" @@ -26077,6 +26668,37 @@ __metadata: languageName: node linkType: hard +"jest-snapshot@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-snapshot@npm:29.5.0" + dependencies: + "@babel/core": ^7.11.6 + "@babel/generator": ^7.7.2 + "@babel/plugin-syntax-jsx": ^7.7.2 + "@babel/plugin-syntax-typescript": ^7.7.2 + "@babel/traverse": ^7.7.2 + "@babel/types": ^7.3.3 + "@jest/expect-utils": ^29.5.0 + "@jest/transform": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/babel__traverse": ^7.0.6 + "@types/prettier": ^2.1.5 + babel-preset-current-node-syntax: ^1.0.0 + chalk: ^4.0.0 + expect: ^29.5.0 + graceful-fs: ^4.2.9 + jest-diff: ^29.5.0 + jest-get-type: ^29.4.3 + jest-matcher-utils: ^29.5.0 + jest-message-util: ^29.5.0 + jest-util: ^29.5.0 + natural-compare: ^1.4.0 + pretty-format: ^29.5.0 + semver: ^7.3.5 + checksum: db9957d9c8607d75bb08302605331b5d90fa738fafeed820ab8ebcb2c90f9e62fb4fec0b4c826c04a37557cbb7a9ed26a10b0c74d46ffedce2d6ae8a9c891b00 + languageName: node + linkType: hard + "jest-util@npm:^25.5.0": version: 25.5.0 resolution: "jest-util@npm:25.5.0" @@ -26146,6 +26768,20 @@ __metadata: languageName: node linkType: hard +"jest-util@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-util@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + ci-info: ^3.2.0 + graceful-fs: ^4.2.9 + picomatch: ^2.2.3 + checksum: c7f1dc8ae82cd9614a31e09806499560b4812beb57589b214241dd213d3cc6d24417593aef2caf2d3d9694925438849fec371ff36ca8a7f1be8438fd41e83373 + languageName: node + linkType: hard + "jest-validate@npm:^25.5.0": version: 25.5.0 resolution: "jest-validate@npm:25.5.0" @@ -26202,6 +26838,20 @@ __metadata: languageName: node linkType: hard +"jest-validate@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-validate@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + camelcase: ^6.2.0 + chalk: ^4.0.0 + jest-get-type: ^29.4.3 + leven: ^3.1.0 + pretty-format: ^29.5.0 + checksum: 7aabde27a9b736df65902a1bb4ec63af518d4c95e12a910e7658140784168f08c662d5babe67dfa70d843dd2096bc08aa7090fef83c7a9d6bb0893793c3a599a + languageName: node + linkType: hard + "jest-watcher@npm:^25.5.0": version: 25.5.0 resolution: "jest-watcher@npm:25.5.0" @@ -26262,6 +26912,22 @@ __metadata: languageName: node linkType: hard +"jest-watcher@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-watcher@npm:29.5.0" + dependencies: + "@jest/test-result": ^29.5.0 + "@jest/types": ^29.5.0 + "@types/node": "*" + ansi-escapes: ^4.2.1 + chalk: ^4.0.0 + emittery: ^0.13.1 + jest-util: ^29.5.0 + string-length: ^4.0.1 + checksum: 6a2e71e720183303913fc34fc24a3f87fca7fcfa638bc6c9109a4808b36251a1cb7fe98b956eb0d9c9ead1ad47c3dc3745289ee89e62c6c615168e92282069ca + languageName: node + linkType: hard + "jest-worker@npm:^25.5.0": version: 25.5.0 resolution: "jest-worker@npm:25.5.0" @@ -26306,6 +26972,18 @@ __metadata: languageName: node linkType: hard +"jest-worker@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-worker@npm:29.5.0" + dependencies: + "@types/node": "*" + jest-util: ^29.5.0 + merge-stream: ^2.0.0 + supports-color: ^8.0.0 + checksum: 4191ec3209cb1d838c931d47c7328fec7279eb7a5d40fa86bb3fac4d34cbad835349bc366150712259a274507fd210ddb450733032394d8e0b19640b3d3ac17d + languageName: node + linkType: hard + "jest@npm:^25.5.2, jest@npm:^25.5.4": version: 25.5.4 resolution: "jest@npm:25.5.4" @@ -26350,6 +27028,25 @@ __metadata: languageName: node linkType: hard +"jest@npm:^29.1.0": + version: 29.5.0 + resolution: "jest@npm:29.5.0" + dependencies: + "@jest/core": ^29.5.0 + "@jest/types": ^29.5.0 + import-local: ^3.0.2 + jest-cli: ^29.5.0 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + bin: + jest: bin/jest.js + checksum: 32e29cfa2373530ed323ea65dfb4fd5172026349be48ebb7a2dc5660adadd1c68f6b0fe2b67cc3ee723cc34e2d4552a852730ac787251b406cf58e37a90f6dac + languageName: node + linkType: hard + "jest@npm:^29.4.1": version: 29.4.1 resolution: "jest@npm:29.4.1" @@ -33042,6 +33739,17 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^29.5.0": + version: 29.5.0 + resolution: "pretty-format@npm:29.5.0" + dependencies: + "@jest/schemas": ^29.4.3 + ansi-styles: ^5.0.0 + react-is: ^18.0.0 + checksum: bcc0190d050196b64e501e5c2b44beb802d79a2b70b6fe6b24ae2d5e0f31237dfcb1f0ab2ada4678829b6ee38507ba292396301aff0a8122e575ffd45d5d037c + languageName: node + linkType: hard + "pretty-hrtime@npm:^1.0.3": version: 1.0.3 resolution: "pretty-hrtime@npm:1.0.3" @@ -33350,6 +34058,13 @@ __metadata: languageName: node linkType: hard +"pure-rand@npm:^6.0.0": + version: 6.0.1 + resolution: "pure-rand@npm:6.0.1" + checksum: d8e046e066d4a980140b501021a8426da0d7a01af901cb03ba8e1863c3960cd01216d997cd2ea7f370f1e9056c31fd88e925679a19787fb874dbc45f51d756e2 + languageName: node + linkType: hard + "q@npm:2.0.x": version: 2.0.3 resolution: "q@npm:2.0.3" @@ -38442,6 +39157,39 @@ __metadata: languageName: node linkType: hard +"ts-jest@npm:^29.1.0": + version: 29.1.0 + resolution: "ts-jest@npm:29.1.0" + dependencies: + bs-logger: 0.x + fast-json-stable-stringify: 2.x + jest-util: ^29.0.0 + json5: ^2.2.3 + lodash.memoize: 4.x + make-error: 1.x + semver: 7.x + yargs-parser: ^21.0.1 + peerDependencies: + "@babel/core": ">=7.0.0-beta.0 <8" + "@jest/types": ^29.0.0 + babel-jest: ^29.0.0 + jest: ^29.0.0 + typescript: ">=4.3 <6" + peerDependenciesMeta: + "@babel/core": + optional: true + "@jest/types": + optional: true + babel-jest: + optional: true + esbuild: + optional: true + bin: + ts-jest: cli.js + checksum: 504d77b13157a4d2f1eebbd0e0f21f2db65fc28039f107fd73453655c029adccba5b22bdd4de0efa58707c1bbd34a67a1a5cceb794e91c3c2c7be4f904c79f9f + languageName: node + linkType: hard + "ts-node@npm:^10.9.1": version: 10.9.1 resolution: "ts-node@npm:10.9.1" @@ -40740,6 +41488,16 @@ __metadata: languageName: node linkType: hard +"write-file-atomic@npm:^4.0.2": + version: 4.0.2 + resolution: "write-file-atomic@npm:4.0.2" + dependencies: + imurmurhash: ^0.1.4 + signal-exit: ^3.0.7 + checksum: a2c282c95ef5d8e1c27b335ae897b5eca00e85590d92a3fd69a437919b7b93ff36a69ea04145da55829d2164e724bc62202cdb5f4b208b425aba0807889375c7 + languageName: node + linkType: hard + "write-file-atomic@npm:^5.0.0": version: 5.0.0 resolution: "write-file-atomic@npm:5.0.0"