From bc3a73a5817aaae0e4ce777046efe0bff3f7e992 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 28 Apr 2024 15:25:53 +0200 Subject: [PATCH 01/52] T Polishes BDD test setup --- packages/test/src/cucumber.test.ts | 4 ---- .../test/src/features/addon-configuration.feature | 10 ++++++++-- .../test/src/features/addon-contribution.feature | 14 ++++++++++++++ .../src/features/compiler-configuration.feature | 4 ++++ .../test/src/features/target-configuration.feature | 2 ++ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/test/src/cucumber.test.ts b/packages/test/src/cucumber.test.ts index b6cc6704..b3d9cb19 100644 --- a/packages/test/src/cucumber.test.ts +++ b/packages/test/src/cucumber.test.ts @@ -9,7 +9,3 @@ import { cliSteps } from "./steps/cli.steps"; const features = loadFeatures("src/features/**/*.feature", { tagFilter: "not @skip" }); autoBindSteps(features, [cliSteps]); - -describe.skip("empty", () => { - it.skip("empty", () => undefined); -}); diff --git a/packages/test/src/features/addon-configuration.feature b/packages/test/src/features/addon-configuration.feature index 5bc43ae0..07580e12 100644 --- a/packages/test/src/features/addon-configuration.feature +++ b/packages/test/src/features/addon-configuration.feature @@ -14,8 +14,10 @@ Feature: Addon configuration # export const activate = () => { # console.log('bar-addon activated'); # }; - And Folder "./addons" contains addons "foo-addon, bar-addon" + Given Folder "./addons" contains addons "foo-addon, bar-addon" + When User calls command "websmith --addons foo-addon" + Then Addons "foo-addon" should be activated in compilation Scenario: Use CLI argument to activate multiple addons @@ -28,8 +30,10 @@ Feature: Addon configuration # export const activate = () => { # console.log('bar-addon activated'); # }; - And Folder "./addons" contains addons "foo-addon, bar-addon" + Given Folder "./addons" contains addons "foo-addon, bar-addon" + When User calls command "websmith --addons foo-addon, bar-addon" + Then Addons "foo-addon, bar-addon" should be activated in compilation Scenario: Use a config file to select active addons @@ -50,6 +54,8 @@ Feature: Addon configuration Given A valid config file named "websmith.config.json" exists in project folder And Config file "websmith.config.json" contains "addons" with "foo-addon" And Folder "./addons" contains addons "foo-addon, bar-addon" + When User calls command "websmith" + Then Addons "foo-addon" should be activated in compilation And Addons "bar-addon" should not be activated \ No newline at end of file diff --git a/packages/test/src/features/addon-contribution.feature b/packages/test/src/features/addon-contribution.feature index 6f3bbbff..0eabe5a4 100644 --- a/packages/test/src/features/addon-contribution.feature +++ b/packages/test/src/features/addon-contribution.feature @@ -7,18 +7,24 @@ Feature: Feature: Addon contribution Scenario: Run Compiler with all addons in default directory Given Folder "./addons" contains addons "foo-addon, bar-addon" + When User calls command "websmith" + Then Addons "bar-addon, foo-addon" should be activated in compilation Scenario: Use CLI argument to select different addons directory Given Folder "./my-addons" contains addons "foo-addon, bar-addon" + When User calls command "websmith --addonsDir ./my-addons" + Then Addons "bar-addon, foo-addon" should be activated in compilation Scenario: Provide generator addon to create additional input files Given Folder "./addons" contains addon examples "example-generator" And A test project "test-project-foo" is provided + When User calls command "websmith" + Then Addons "example-generator" should be activated in compilation And A file "./dist/foo-added.js" exists containing string "const foo = ()" @@ -26,7 +32,9 @@ Feature: Feature: Addon contribution Given Folder "./addons" contains addon examples "example-processor" And A test project "test-project-foobar" is provided And A file "./src/foobar.ts" exists containing string "function foobar(): string {" + When User calls command "websmith" + Then Addons "example-processor" should be activated in compilation And A file content "./src/foobar.ts" exists containing string "export function foobar(): string {" And A file "./dist/foobar.js" exists containing string "export function foobar() {" @@ -37,7 +45,9 @@ Feature: Feature: Addon contribution Given Folder "./addons" contains addon examples "example-transformer" And A test project "test-project-foobar" is provided And A file "./src/foobar.ts" exists containing string "function foobar(): string {" + When User calls command "websmith" + Then Addons "example-transformer" should be activated in compilation And A file "./dist/foobar.js" exists containing string "function barfoo() {" And A file "./dist/whatever.js" exists containing string "function whatever() {" @@ -45,13 +55,17 @@ Feature: Feature: Addon contribution Scenario: Provide result processor addon to add comment to generated files Given Folder "./addons" contains addon examples "example-result-processor" And A test project "test-project-one" is provided + When User calls command "websmith" + Then Addons "example-result-processor" should be activated in compilation And A file "./dist/named-functions.json" exists containing names "one, two, three" Scenario: Provide a YAML generator addon to create additional documentation Given Folder "./addons" contains addon examples "export-yaml-generator" And A test project "test-project-one" is provided + When User calls command "websmith" + Then Addons "export-yaml-generator" should be activated in compilation And A file "./dist/output.yaml" exists containing names "one, two, three" diff --git a/packages/test/src/features/compiler-configuration.feature b/packages/test/src/features/compiler-configuration.feature index b4328092..b3a9a060 100644 --- a/packages/test/src/features/compiler-configuration.feature +++ b/packages/test/src/features/compiler-configuration.feature @@ -5,7 +5,9 @@ Feature: Compiler configuration Scenario: Use CLI argument to compile a project Given A test project "test-project-one" is provided + When User calls command "websmith" + Then A file "./dist/one.js" exists containing string "const one = () =>" And A file "./dist/two.js" exists containing string "const two = () =>" And A file "./dist/three.js" exists containing string "const three = () =>" @@ -15,7 +17,9 @@ Feature: Compiler configuration And A valid config file named "my-config.json" exists in project folder And Config file "my-config.json" contains "addons" with "foo-addon" And Folder "./addons" contains addons "foo-addon, bar-addon" + When User calls command "websmith --config my-config.json" + Then Addons "foo-addon" should be activated in compilation And Addons "bar-addon" should not be activated # TODO: And A file "./lib/one.js" exists containing string "const one = () =>" diff --git a/packages/test/src/features/target-configuration.feature b/packages/test/src/features/target-configuration.feature index 531dd500..b26246f3 100644 --- a/packages/test/src/features/target-configuration.feature +++ b/packages/test/src/features/target-configuration.feature @@ -9,6 +9,8 @@ Feature: Target configuration And Folder "./addons" contains addon examples "foobar-replace-transformer" And Config file "websmith.config.json" contains target "foobar" And Target project contains a module "target.ts" with a function is named "foobar" + When User calls command "websmith --targets foobar" + Then A file "./dist/target.js" exists containing string "barfoo" And Every call to function "foobar" in "./src/target.ts" should be replaced with "barfoo" in "./dist/target.js" From 955f6d91281f0d969c9a6c0dbe2a3c1089eb7a01 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 28 Apr 2024 22:19:29 +0200 Subject: [PATCH 02/52] [WIP]** Introduces Testing API --- packages/compiler/src/options.ts | 5 +- packages/core/src/compiler/Compiler.ts | 2 +- .../src/compiler/addons/AddonRegistry.spec.ts | 14 +- .../core/src/compiler/addons/AddonRegistry.ts | 96 +++++---- packages/core/tsconfig.json | 2 +- packages/test/jest.config.js | 3 +- packages/test/package.json | 1 + packages/test/src/setup/config.ts | 24 +++ packages/test/src/setup/copy.ts | 35 ++++ packages/test/src/setup/environment.spec.ts | 23 +++ packages/test/src/setup/environment.ts | 161 +++++++++++++++ packages/test/src/setup/execute.ts | 24 +++ packages/test/src/setup/expect.ts | 20 ++ packages/test/src/setup/index.ts | 7 + packages/test/src/setup/paths.ts | 10 + packages/test/src/setup/values.ts | 10 + packages/test/src/steps/cli.steps.ts | 4 +- .../test/src/test-examples/bar-addon.test.ts | 102 ++++++++++ packages/testing/jest.config.js | 5 +- packages/testing/package.json | 4 +- packages/testing/src/compilation/copy.ts | 35 ++++ .../src/compilation/environment.spec.ts | 83 ++++++++ .../testing/src/compilation/environment.ts | 140 +++++++++++++ .../testing/src/compilation/resolve-path.ts | 10 + packages/testing/src/compile-options.ts | 8 +- packages/testing/test/__setup__/fusion-fs.ts | 190 ++++++++++++++++++ packages/testing/test/__setup__/jest.setup.ts | 14 ++ pnpm-lock.yaml | 49 +++++ 28 files changed, 1017 insertions(+), 64 deletions(-) create mode 100644 packages/test/src/setup/config.ts create mode 100644 packages/test/src/setup/copy.ts create mode 100644 packages/test/src/setup/environment.spec.ts create mode 100644 packages/test/src/setup/environment.ts create mode 100644 packages/test/src/setup/execute.ts create mode 100644 packages/test/src/setup/expect.ts create mode 100644 packages/test/src/setup/index.ts create mode 100644 packages/test/src/setup/paths.ts create mode 100644 packages/test/src/setup/values.ts create mode 100644 packages/test/src/test-examples/bar-addon.test.ts create mode 100644 packages/testing/src/compilation/copy.ts create mode 100644 packages/testing/src/compilation/environment.spec.ts create mode 100644 packages/testing/src/compilation/environment.ts create mode 100644 packages/testing/src/compilation/resolve-path.ts create mode 100644 packages/testing/test/__setup__/fusion-fs.ts create mode 100644 packages/testing/test/__setup__/jest.setup.ts diff --git a/packages/compiler/src/options.ts b/packages/compiler/src/options.ts index 94fb794f..df2055d0 100644 --- a/packages/compiler/src/options.ts +++ b/packages/compiler/src/options.ts @@ -4,14 +4,13 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { Reporter } from "@quatico/websmith-api"; import { AddonRegistry, CompilerOptions, NoReporter, resolveCompilationConfig, - resolveProjectConfig as resolveTsConfig, resolveTargets, + resolveProjectConfig as resolveTsConfig, updateCompilerOptions, } from "@quatico/websmith-core"; import { dirname, join } from "path"; @@ -29,7 +28,7 @@ const DEFAULTS = { watch: false, }; -export const createOptions = (args: CompilerArguments, reporter: Reporter = new NoReporter(), system: ts.System = ts.sys): CompilerOptions => { +export const createOptions = (args: CompilerArguments, reporter = new NoReporter(), system = ts.sys): CompilerOptions => { const tsconfig: ts.ParsedCommandLine = resolveTsConfig(args.project ?? DEFAULTS.project, system); const compilationConfig = resolveCompilationConfig(args.config ?? DEFAULTS.config, reporter, system); diff --git a/packages/core/src/compiler/Compiler.ts b/packages/core/src/compiler/Compiler.ts index 1c58e9e1..1dc9736d 100644 --- a/packages/core/src/compiler/Compiler.ts +++ b/packages/core/src/compiler/Compiler.ts @@ -187,7 +187,7 @@ export class Compiler { } const ctx = this.createCompilationContext(this.options, target, this.dependencyCallback); - this.options.addons.getAddons(target).forEach(addon => { + this.options.addons.getAvailableAddons(target).forEach(addon => { addon.activate(ctx); }); this.contextMap.set(target, ctx); diff --git a/packages/core/src/compiler/addons/AddonRegistry.spec.ts b/packages/core/src/compiler/addons/AddonRegistry.spec.ts index 202de567..3960c2c2 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.spec.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.spec.ts @@ -54,7 +54,7 @@ describe("getAddons", () => { it("returns empty addons w/ empty addons directory", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAddons()).toEqual([]); + expect(testObj.getAvailableAddons()).toEqual([]); }); it("returns addons w/ single addon in addon directory", () => { @@ -69,7 +69,7 @@ describe("getAddons", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAddons().map(it => it.name)).toEqual(["expected"]); + expect(testObj.getAvailableAddons().map(it => it.name)).toEqual(["expected"]); }); it("returns addons w/ multiple addons in addon directory", () => { @@ -100,7 +100,7 @@ describe("getAddons", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAddons().map(it => it.name)).toEqual(["one", "two", "three"]); + expect(testObj.getAvailableAddons().map(it => it.name)).toEqual(["one", "two", "three"]); }); it("returns valid addons w/ invalid and valid addons in addon directory", () => { @@ -123,7 +123,7 @@ describe("getAddons", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAddons().map(it => it.name)).toEqual(["expected"]); + expect(testObj.getAvailableAddons().map(it => it.name)).toEqual(["expected"]); }); it("returns no addons w/ empty files in addon directory", () => { @@ -138,7 +138,7 @@ describe("getAddons", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAddons()).toEqual([]); + expect(testObj.getAvailableAddons()).toEqual([]); }); it("reports warning w/ non-existing addons name", () => { @@ -150,7 +150,7 @@ describe("getAddons", () => { config: { addons: ["does-not-exist"], configFilePath: "" }, reporter, system, - }).getAddons(); + }).getAvailableAddons(); expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons: "does-not-exist".')); }); @@ -164,7 +164,7 @@ describe("getAddons", () => { config: { targets: { target: { addons: ["does-not-exist"] } }, configFilePath: "" }, reporter, system, - }).getAddons("target"); + }).getAvailableAddons("target"); expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "target": "does-not-exist".')); }); diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index d69fd4b1..36a79f2d 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -20,24 +20,21 @@ export type AddonRegistryOptions = { export class AddonRegistry { private addons: string[]; - private config?: CompilationConfig; private availableAddons: Map; - private reporter: Reporter; + private options: AddonRegistryOptions; constructor(options: AddonRegistryOptions) { - const { addons, addonsDir, config, reporter, system } = options; + this.options = options; this.addons = - addons + options.addons ?.split(",") .map(it => it.trim()) .filter(it => it.length > 0) ?? []; - this.config = config; - this.availableAddons = findAddons(addonsDir, reporter, system); - this.reporter = reporter; + this.availableAddons = this.findAddons(); } - public getAddons(target?: string): CompilerAddon[] { - const expected = getAddonNames(target, this.addons, this.config); + public getAvailableAddons(target?: string): CompilerAddon[] { + const expected = getAddonNames(target, this.addons, this.options.config); if (expected.length > 0) { this.reportMissingAddons(target, expected); return expected.map(it => this.availableAddons.get(it)).filter(it => it !== undefined) as CompilerAddon[]; @@ -45,16 +42,60 @@ export class AddonRegistry { return Array.from(this.availableAddons.values()); } + public getAddonDir(): string { + return this.options.addonsDir; + } + + public refresh(): this { + this.availableAddons = this.findAddons(); + return this; + } + private reportMissingAddons(target: string | undefined, expected: string[]): void { + const { reporter } = this.options; const missing = expected.filter(name => !this.availableAddons.has(name)); if (missing.length > 0) { if (target && target !== "*") { - this.reporter.reportDiagnostic(new WarnMessage(`Missing addons for target "${target}": "${missing.join(", ")}".`)); + reporter.reportDiagnostic(new WarnMessage(`Missing addons for target "${target}": "${missing.join(", ")}".`)); } else { - this.reporter.reportDiagnostic(new WarnMessage(`Missing addons: "${missing.join(", ")}".`)); + reporter.reportDiagnostic(new WarnMessage(`Missing addons: "${missing.join(", ")}".`)); } } } + private findAddons(): Map { + const { addonsDir, reporter, system } = this.options; + const map = new Map(); + + if (addonsDir && !system.directoryExists(addonsDir)) { + reporter.reportDiagnostic(new WarnMessage(`Addons directory "${addonsDir}" does not exist.`)); + return map; + } + + if (addonsDir) { + system + .readDirectory(addonsDir, [".js", ".jsx"]) + .filter(ad => basename(ad, extname(ad)).toLocaleLowerCase() === "addon") + .forEach(it => { + const importPath = system.resolvePath(it); + const modulePath = extname(importPath).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) + ? importPath.replace(extname(importPath), "") + : importPath; + // eslint-disable-next-line @typescript-eslint/no-var-requires + const activator = require(modulePath).activate; + const name = it + .replace(path.sep + basename(it), "") + .split(path.sep) + .slice(-1)[0]; + if (name && map.has(name)) { + reporter.reportDiagnostic(new WarnMessage(`Duplicate addon name "${name}" in "${addonsDir}".`)); + } + if (name && activator && !map.has(name)) { + map.set(name, { name, activate: activator }); + } + }); + } + return map; + } } const getAddonNames = (target: string | undefined, expectedAddons: string[], config?: CompilationConfig): string[] => { @@ -72,36 +113,3 @@ const getAddonNames = (target: string | undefined, expectedAddons: string[], con } return []; }; - -const findAddons = (addonsDir: string, reporter: Reporter, system: ts.System): Map => { - const map = new Map(); - - if (addonsDir && !system.directoryExists(addonsDir)) { - reporter.reportDiagnostic(new WarnMessage(`Addons directory "${addonsDir}" does not exist.`)); - return map; - } - - if (addonsDir) { - system - .readDirectory(addonsDir, [".js", ".jsx", ".ts", ".tsx"]) - .filter(ad => basename(ad, extname(ad)).toLocaleLowerCase() === "addon") - .forEach(it => { - const importPath = system.resolvePath(it); - // eslint-disable-next-line @typescript-eslint/no-var-requires - const activator = require(extname(importPath).match(/^(?!.*\.d\.tsx?$).*\.[tj]sx?$/g) - ? importPath.replace(extname(importPath), "") - : importPath).activate; - const name = it - .replace(path.sep + basename(it), "") - .split(path.sep) - .slice(-1)[0]; - if (name && map.has(name)) { - reporter.reportDiagnostic(new WarnMessage(`Duplicate addon name "${name}" in "${addonsDir}".`)); - } - if (name && activator && !map.has(name)) { - map.set(name, { name, activate: activator }); - } - }); - } - return map; -}; diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index b91e7a2c..26a05244 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -5,7 +5,7 @@ "outDir": "./lib", "typeRoots": ["@types", "./node_modules/@types", "../../node_modules/@types"] /* List of folders to include type definitions from. */, "noEmit": false, - "moduleResolution": "node", + "moduleResolution": "node" }, "exclude": ["src/**/*.spec.ts", "test/**/*.ts"], "include": ["src/**/*.ts"] diff --git a/packages/test/jest.config.js b/packages/test/jest.config.js index 1c85f075..8e1be420 100644 --- a/packages/test/jest.config.js +++ b/packages/test/jest.config.js @@ -12,9 +12,10 @@ module.exports = { "@quatico/websmith-core": "/../core/src", "@quatico/websmith-compiler": "/../compiler/src", }, + prettierPath: null, roots: ["/src/"], testEnvironment: "node", - testMatch: ["**/cucumber.test.ts", "test/.*\\.test\\.(j|t)sx?$"], + testRegex: "src/.*(test|spec)\\.(js|ts)$", transform: { "^.+\\.(j|t)s$": [ "@swc/jest", diff --git a/packages/test/package.json b/packages/test/package.json index fb3456c3..c7aa549e 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -19,6 +19,7 @@ "@quatico/websmith-api": "workspace:^", "@quatico/websmith-compiler": "workspace:^", "@quatico/websmith-core": "workspace:^", + "@quatico/websmith-testing": "workspace:^", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", diff --git a/packages/test/src/setup/config.ts b/packages/test/src/setup/config.ts new file mode 100644 index 00000000..e07711c6 --- /dev/null +++ b/packages/test/src/setup/config.ts @@ -0,0 +1,24 @@ +import ts from "typescript"; +import { resolvePath } from "./paths"; +import { stringToArray } from "./values"; + +export const websmithConfig = (system: ts.System, configPath: string, content?: object) => { + const resolvedConfigPath = resolvePath(system, configPath); + system.writeFile(resolvedConfigPath, JSON.stringify({ addonsDir: "./addons", ...content })); +}; + +export const setConfig = (system: ts.System, configPath: string, cfgProp: string, cfgValue: string) => { + const resolvedConfigPath = resolvePath(system, configPath); + const content = JSON.parse(system.readFile(resolvedConfigPath, "utf-8") ?? "{}") as Record; + content[cfgProp] = stringToArray(cfgValue); + system.writeFile(resolvedConfigPath, JSON.stringify(content)); +}; + +export const setTargets = (system: ts.System, configPath: string, targetNames: string) => { + const resolvedConfigPath = resolvePath(system, configPath); + const content = JSON.parse(system.readFile(resolvedConfigPath, "utf-8") ?? "{}") as { targets?: Record }; + const targets: string[] = stringToArray(targetNames); + + content.targets = { ...(content.targets ?? {}), ...targets.map(it => ({ [it]: {} })) }; + system.writeFile(resolvedConfigPath, JSON.stringify(content)); +}; diff --git a/packages/test/src/setup/copy.ts b/packages/test/src/setup/copy.ts new file mode 100644 index 00000000..33e8732f --- /dev/null +++ b/packages/test/src/setup/copy.ts @@ -0,0 +1,35 @@ +import { basename, join } from "path"; +import ts from "typescript"; + +const copyFileSync = (system: ts.System, source: string, target: string) => { + let targetFile = target; + // If target is a directory, a new file with the same name will be created + if (system.directoryExists(target)) { + targetFile = join(target, basename(source)); + } + const fileContent = system.readFile(source); + if (fileContent) { + system.writeFile(targetFile, fileContent); + } +}; + +export const copyFolderSync = (system: ts.System, source: string, target: string) => { + let files = []; + // Check if folder needs to be created or integrated + const targetFolder = join(target, basename(source)); + if (!system.directoryExists(targetFolder)) { + system.createDirectory(targetFolder); + } + // Copy + if (system.directoryExists(source)) { + files = system.readDirectory(source); + files.forEach(file => { + const curSource = join(source, file); + if (system.directoryExists(curSource)) { + copyFolderSync(system, curSource, targetFolder); + } else { + copyFileSync(system, curSource, targetFolder); + } + }); + } +}; diff --git a/packages/test/src/setup/environment.spec.ts b/packages/test/src/setup/environment.spec.ts new file mode 100644 index 00000000..ed0f0dcd --- /dev/null +++ b/packages/test/src/setup/environment.spec.ts @@ -0,0 +1,23 @@ +import { setUp } from "./environment"; +import { activeAddons } from "./expect"; + +describe("installAddons", () => { + it("should install addon successfully", () => { + const { addAddons, cleanUp, rootDir } = setUp("/", { + virtual: true, + files: { + "/addons/tsconfig.json": "{}", + "./addons/target-addon/addon.ts": ` + export const activate = () => {}; + `, + "./tsconfig.json": "{}", + }, + }); + + const actual = addAddons("target-addon", "../test-data/addons/"); + + cleanUp(rootDir); + + expect(activeAddons(actual)).toEqual(["target-addon"]); + }); +}); diff --git a/packages/test/src/setup/environment.ts b/packages/test/src/setup/environment.ts new file mode 100644 index 00000000..a5836519 --- /dev/null +++ b/packages/test/src/setup/environment.ts @@ -0,0 +1,161 @@ +import type { Reporter } from "@quatico/websmith-api"; +import { CompilerArguments, createOptions } from "@quatico/websmith-compiler"; +import { AddonRegistry, Compiler, createBrowserSystem } from "@quatico/websmith-core"; +import { dirname, join } from "path"; +import ts from "typescript"; +import { copyFolderSync } from "./copy"; +import { fileContent } from "./expect"; +import { resolvePath } from "./paths"; +import { stringToArray } from "./values"; + +export interface WebsmithEnv { + compiler: Compiler; + rootDir: string; + system: ts.System; + cleanUp: (path?: string) => void; + addAddons: (addonNames: string, templateFolder?: string, addonsDir?: string) => AddonRegistry; + setProject: (projectName: string, targetDir?: string, templateFolder?: string) => string; + sourceFile: (fileName: string, content: string) => string; +} + +export type WebsmithOptions = { + compilerArguments?: CompilerArguments; + files?: Record; + reporter?: Reporter; + useCaseSensitiveFileNames?: boolean; + virtual?: boolean; +}; + +export const setUp = (rootDir: string, options?: WebsmithOptions): WebsmithEnv => { + const { virtual = false, compilerArguments = {}, useCaseSensitiveFileNames, files, reporter } = options ?? {}; + + const system = virtual ? createBrowserSystem(files, useCaseSensitiveFileNames) : ts.sys; + + if (files) { + if (!virtual) { + throw new Error("Cannot provide files in non-virtual mode."); + } + + const addonsToCompile = Object.keys(files) + .filter(it => it.endsWith("/addon.ts")) + .map(it => dirname(it)); + addonsToCompile.forEach(curDir => { + const addonCompiler = new Compiler( + { + ...createOptions( + { + addons: "", + addonsDir: "./do-not-use-addons", + buildDir: curDir, + }, + reporter, + system + ), + project: { module: ts.ModuleKind.ES2015, target: ts.ScriptTarget.ES5 }, + tsconfig: { options: {}, fileNames: system.readDirectory(curDir).filter(it => it.endsWith(".ts")), errors: [] }, + }, + system + ); + addonCompiler.compile(); + }); + + if (!fileContent(system, "./addons/target-addon/addon.js", "/")) { + throw new Error(`Addons not compiled. ${system.readDirectory("./addons")}`); + } + + jest.mock( + "/addons/target-addon/addon", + () => { + return eval(files["./addons/target-addon/addon.js"]); + }, + { virtual: true } + ); + } + + const compileOptions = createOptions({ buildDir: "/", project: "./tsconfig.json", ...compilerArguments }, reporter, system); + const resolved = resolvePath(system, rootDir); + const compiler = new Compiler(compileOptions, system); + + if (!system.directoryExists(resolved)) { + system.createDirectory(resolved); + } + + process.chdir(resolved); + + // if (withDefaults && !existsSync(join(projectDir, "src"))) { + // mkdirSync(join(projectDir, "src")); + // } + // process.chdir(projectDir); + + // if (withDefaults && !existsSync(join(projectDir, "websmith.config.json"))) { + // writeFileSync( + // join(projectDir, "websmith.config.json"), + // JSON.stringify({ + // addonsDir: "./addons", + // }) + // ); + // } + + // if (withDefaults && !existsSync(join(projectDir, "tsconfig.json"))) { + // writeFileSync( + // join(projectDir, "tsconfig.json"), + // JSON.stringify({ + // compilerOptions: { + // target: "ESNEXT", + // module: "ESNEXT", + // lib: ["es2017", "es7", "es6", "dom"], + // declaration: true, + // outDir: "dist", + // strict: true, + // esModuleInterop: true, + // }, + // include: ["src"], + // exclude: ["node_modules", "dist"], + // }) + // ); + // } + + const cleanUp = (path?: string): void => { + const target = path ?? resolved; + if (system.fileExists(target)) { + system.readDirectory(target).forEach(it => system.deleteFile!(it)); + } + }; + + const installAddons = ( + addonNames: string, + templateFolder = "../test-data/addons/", + addonsDir = compileOptions.addons.getAddonDir() + ): AddonRegistry => { + const addonsDirPath = resolvePath(system, addonsDir); + stringToArray(addonNames).forEach(addon => { + copyFolderSync(system, join(__dirname, templateFolder, addon), addonsDirPath); + }); + const registry = compileOptions.addons.refresh(); + // @ts-expect-error - private method + compiler.createTargetContextsIfNecessary(); + + return registry; + }; + + const installProject = (projectName: string, targetDir?: string, templateFolder = "../test-data/projects/"): string => { + const target = targetDir ?? process.cwd(); + copyFolderSync(system, join(__dirname, templateFolder, projectName), target); + return resolvePath(system, `${target}/${projectName}`); + }; + + const sourceFile = (fileName: string, content: string): string => { + system.writeFile(resolvePath(system, "src", fileName), content); + return content; + }; + + return { + rootDir: resolved, + compiler, + system, + cleanUp, + addAddons, + sourceFile, + setProject, + }; +}; diff --git a/packages/test/src/setup/execute.ts b/packages/test/src/setup/execute.ts new file mode 100644 index 00000000..c5f07416 --- /dev/null +++ b/packages/test/src/setup/execute.ts @@ -0,0 +1,24 @@ +import { createOptions } from "@quatico/websmith-compiler"; +import { Compiler } from "@quatico/websmith-core"; +import parseArgs from "minimist"; + +export const execute = (command: string) => { + let cmd: string = command; + if (cmd === "websmith") { + cmd = ""; + } else if (cmd.startsWith("websmith ")) { + cmd = cmd.replace("websmith ", ""); + } + + const args = cmd + .replace(", ", ",") + .split(" ") + .map(it => it.trim()) + .filter(it => it.length > 0); + + const compiler = new Compiler(createOptions({ ...parseArgs(args), buildDir: "./dist", project: "./tsconfig.json" })); + compiler.compile(); + const context = compiler.getContext()!; + + return { compiler, context }; +}; diff --git a/packages/test/src/setup/expect.ts b/packages/test/src/setup/expect.ts new file mode 100644 index 00000000..3b524a98 --- /dev/null +++ b/packages/test/src/setup/expect.ts @@ -0,0 +1,20 @@ +import { AddonRegistry, Compiler } from "@quatico/websmith-core"; +import ts from "typescript"; +import { resolvePath } from "./paths"; + +export const activeAddons = (compilerOrRegistry: Compiler | AddonRegistry) => { + const target = isCompiler(compilerOrRegistry) ? compilerOrRegistry.getOptions().addons : compilerOrRegistry; + return target.getAvailableAddons().map(cur => cur.name); +}; + +export const fileContent = (system: ts.System, filePath: string, projectDir = process.cwd()): string | undefined => + system.readFile(resolvePath(system, projectDir, `${filePath}`), "utf-8"); + +export const pathExists = (system: ts.System, ...filePaths: string[]): boolean => + filePaths.reduce( + (acc, it) => acc && (system.fileExists(resolvePath(system, `${it}`)) || system.directoryExists(resolvePath(system, `${it}`))), + true + ); + +const isCompiler = (compilerOrRegistry: Compiler | AddonRegistry): compilerOrRegistry is Compiler => + compilerOrRegistry instanceof Compiler && !("getAddons" in compilerOrRegistry); diff --git a/packages/test/src/setup/index.ts b/packages/test/src/setup/index.ts new file mode 100644 index 00000000..b0081c31 --- /dev/null +++ b/packages/test/src/setup/index.ts @@ -0,0 +1,7 @@ +export * from "./config"; +export * from "./copy"; +export * from "./execute"; +export * from "./expect"; +export * from "./environment"; +export * from "./paths"; +export * from "./values"; diff --git a/packages/test/src/setup/paths.ts b/packages/test/src/setup/paths.ts new file mode 100644 index 00000000..097bb210 --- /dev/null +++ b/packages/test/src/setup/paths.ts @@ -0,0 +1,10 @@ +import { isAbsolute, join } from "path"; +import ts from "typescript"; + +export const resolvePath = (fs: ts.System, ...pathSegments: string[]) => { + let resolvedPath = join(...pathSegments); + if (!isAbsolute(resolvedPath)) { + resolvedPath = join(fs.getCurrentDirectory(), ...pathSegments); + } + return resolvedPath; +}; diff --git a/packages/test/src/setup/values.ts b/packages/test/src/setup/values.ts new file mode 100644 index 00000000..1a024ad7 --- /dev/null +++ b/packages/test/src/setup/values.ts @@ -0,0 +1,10 @@ +export const stringToArray = (valueOrCommaSeparated: string): string[] => { + let result: string[] = [valueOrCommaSeparated]; + if (valueOrCommaSeparated.indexOf(",") > -1) { + result = valueOrCommaSeparated + .split(",") + .map(cur => cur.trim()) + .filter(cur => cur.length > 0); + } + return result; +}; diff --git a/packages/test/src/steps/cli.steps.ts b/packages/test/src/steps/cli.steps.ts index 62ec880e..eb34809a 100644 --- a/packages/test/src/steps/cli.steps.ts +++ b/packages/test/src/steps/cli.steps.ts @@ -126,7 +126,7 @@ export const cliSteps: StepDefinitions = ({ given, when, then }) => { expect( compiler .getOptions() - .addons.getAddons() + .addons.getAvailableAddons() .map(cur => cur.name) ).toEqual(addons); }); @@ -138,7 +138,7 @@ export const cliSteps: StepDefinitions = ({ given, when, then }) => { expect( compiler .getOptions() - .addons.getAddons() + .addons.getAvailableAddons() .map(cur => cur.name) ).not.toContain(addon); }); diff --git a/packages/test/src/test-examples/bar-addon.test.ts b/packages/test/src/test-examples/bar-addon.test.ts new file mode 100644 index 00000000..1af1c69b --- /dev/null +++ b/packages/test/src/test-examples/bar-addon.test.ts @@ -0,0 +1,102 @@ +import { activeAddons, execute, fileContent, pathExists, setUp } from "../setup"; + +const { rootDir, cleanUp, compiler, addAddons, setProject, system } = setUp("__TEMP__"); + +beforeAll(() => { + addAddons("foo-addon", "../test-data/addons/"); +}); + +afterAll(() => { + cleanUp(rootDir); +}); + +describe("test-project-foo", () => { + let projectDir: string; + beforeEach(() => { + projectDir = setProject("test-project-foo", rootDir, "../test-data/projects/"); + }); + + afterEach(() => { + cleanUp(projectDir); + }); + + it("should install addon successfully", () => { + expect(activeAddons(compiler)).toContain("foo-addon"); + }); + + it("should contain source file", () => { + const actual = fileContent(system, projectDir, "src/foo.ts"); + + expect(actual).toMatchInlineSnapshot(` + "export const foo = (): void => { + console.log("foo"); + }; + " + `); + }); + + it("should compile source file content", () => { + execute("websmith compiler"); + + expect(fileContent(system, "dist/foo.js")).toMatchInlineSnapshot(` + "export const foo = () => { + console.log("foo"); + }; + " + `); + }); +}); + +describe("test-project-foobar", () => { + beforeEach(() => { + setProject("test-project-foobar"); + }); + + afterEach(() => { + cleanUp(); + }); + + it("should contain source files", () => { + expect(pathExists(system, "src/foobar.ts", "src/whatever.ts")).toBe(true); + }); + + it("should compile foobar.ts content", () => { + execute("websmith compiler"); + + expect(fileContent(system, "dist/foobar.js")).toMatchInlineSnapshot(` + ""use strict"; + /* eslint-disable @typescript-eslint/no-unused-vars */ + function foobar() { + console.log("foobar"); + return "foobar"; + } + " + `); + }); +}); + +describe("test-project-one", () => { + let projectDir: string; + beforeEach(() => { + projectDir = setProject("test-project-one", rootDir, "../test-data/projects/"); + }); + + afterEach(() => { + cleanUp(projectDir); + }); + + it("should contain source file", () => { + expect(pathExists(system, "src/one.ts", "src/two.ts", "src/three.ts")).toBe(true); + }); + + it("should compile one.ts content", () => { + execute("websmith compiler"); + + expect(fileContent(system, "dist/one.js")).toMatchInlineSnapshot(` + "export const one = () => { + console.log("one"); + }; + " + `); + }); +}); diff --git a/packages/testing/jest.config.js b/packages/testing/jest.config.js index 3e7bfd16..ef5df41d 100644 --- a/packages/testing/jest.config.js +++ b/packages/testing/jest.config.js @@ -1,3 +1,5 @@ +const { prettierPath } = require("../../jest.config"); + /* * --------------------------------------------------------------------------------------------- * Copyright (c) Quatico Solutions AG. All rights reserved. @@ -13,8 +15,9 @@ module.exports = { "@quatico/websmith-api": "/../api/src", "@quatico/websmith-core": "/../core/src", }, + prettierPath: null, testRegex: "src/.*spec\\.(js|ts)$", - setupFilesAfterEnv: ["/../../jest.setup.ts"], + setupFilesAfterEnv: ["/test/__setup__/jest.setup.ts", "/../../jest.setup.ts"], testEnvironmentOptions: { url: "http://localhost/" }, transform: { "^.+\\.(js|ts)$": [ diff --git a/packages/testing/package.json b/packages/testing/package.json index 89e3d313..90a2e958 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -32,7 +32,9 @@ "dist": "pnpm clean && pnpm lint && pnpm test && cross-env-shell NODE_ENV=production \"pnpm build\"" }, "dependencies": { - "@quatico/websmith-core": "workspace:^" + "@quatico/websmith-core": "workspace:^", + "@quatico/websmith-api": "workspace:^", + "@quatico/websmith-compiler": "workspace:^" }, "devDependencies": { "@eslint/js": "^9.1.1", diff --git a/packages/testing/src/compilation/copy.ts b/packages/testing/src/compilation/copy.ts new file mode 100644 index 00000000..33e8732f --- /dev/null +++ b/packages/testing/src/compilation/copy.ts @@ -0,0 +1,35 @@ +import { basename, join } from "path"; +import ts from "typescript"; + +const copyFileSync = (system: ts.System, source: string, target: string) => { + let targetFile = target; + // If target is a directory, a new file with the same name will be created + if (system.directoryExists(target)) { + targetFile = join(target, basename(source)); + } + const fileContent = system.readFile(source); + if (fileContent) { + system.writeFile(targetFile, fileContent); + } +}; + +export const copyFolderSync = (system: ts.System, source: string, target: string) => { + let files = []; + // Check if folder needs to be created or integrated + const targetFolder = join(target, basename(source)); + if (!system.directoryExists(targetFolder)) { + system.createDirectory(targetFolder); + } + // Copy + if (system.directoryExists(source)) { + files = system.readDirectory(source); + files.forEach(file => { + const curSource = join(source, file); + if (system.directoryExists(curSource)) { + copyFolderSync(system, curSource, targetFolder); + } else { + copyFileSync(system, curSource, targetFolder); + } + }); + } +}; diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts new file mode 100644 index 00000000..35512821 --- /dev/null +++ b/packages/testing/src/compilation/environment.spec.ts @@ -0,0 +1,83 @@ +import ts from "typescript"; +import { compilationEnv, type CompilationEnv } from "./environment"; + +describe("compilationEnv", () => { + let testObj: CompilationEnv; + + afterEach(() => { + testObj.cleanUp(); + }); + + it("should return a new compilation environment with defaults", () => { + testObj = compilationEnv("expected"); + + expect(testObj.getRootDir().endsWith("/expected")).toBe(true); + expect(testObj.getCompiler()).toBeDefined(); + expect(testObj.getSystem()).toBe(ts.sys); + }); + + it("should return a new compilation environment with default compiler options", () => { + testObj = compilationEnv("/target"); + + const actual = testObj.getCompilerOptions(); + + expect(actual).toMatchObject({ + buildDir: "/", + project: { + configFilePath: "./tsconfig.json", + module: ts.ModuleKind.ESNext, + target: ts.ScriptTarget.ESNext, + }, + sourceMap: false, + targets: ["*"], + transpileOnly: false, + tsconfig: { + errors: [], + options: {}, + }, + watch: false, + }); + }); + + it("should return a new compilation environment with custom compiler options", () => { + testObj = compilationEnv("/target", { compilerOptions: { buildDir: "/expected-src", project: { outDir: "/expected-out" } } }); + + const actual = testObj.getCompilerOptions(); + + expect(actual).toMatchObject({ + buildDir: "/expected-src", + project: { + configFilePath: "./tsconfig.json", + module: ts.ModuleKind.ESNext, + target: ts.ScriptTarget.ESNext, + outDir: "/expected-out", + }, + }); + }); + + it("should return a new compilation environment with default addons", () => { + testObj = compilationEnv("/target"); + + const actual = testObj.getAddons(); + + expect(actual.getAddonDir()).toBe("./addons"); + expect(actual.getAvailableAddons()).toEqual([]); + }); + + it("should return a new compilation environment with valid custom addons", () => { + testObj = compilationEnv("/target").addAddon("expected-addon", `export const activate = () => {};`); + + const actual = testObj.getAddons().getAvailableAddons(); + + expect(testObj.getSystem().readDirectory("/target")).toEqual(["/addons/expected-addon/addon.ts"]); + expect(actual).toEqual(["expected-addon"]); + }); + + it("should return a new compilation environment with valid custom addonsXXX", () => { + testObj = compilationEnv("/target").addAddon("expected-addon", `export const activate = () => {};`); + + const actual = testObj.getAddons().getAvailableAddons(); + + expect(actual).toEqual(["expected-addon"]); + }); +}); diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts new file mode 100644 index 00000000..288ae22a --- /dev/null +++ b/packages/testing/src/compilation/environment.ts @@ -0,0 +1,140 @@ +import { Compiler, CompilerOptions } from "@quatico/websmith-core"; +import { dirname, join } from "path"; +import ts from "typescript"; +import { compileOptions } from "../compile-options"; +import { copyFolderSync } from "./copy"; +import { resolvePath } from "./resolve-path"; +// import fs from "memfs"; + +export class CompilationEnv { + private compiler: Compiler; + private rootDir: string; + private system: ts.System; + + constructor(rootDir: string, options?: CompilationOptions) { + const { virtual = true, compilerOptions = {}, files } = options ?? {}; + this.system = ts.sys; + this.rootDir = resolvePath(this.system, rootDir); + + this.addFiles(files); + + const compOptions = compileOptions(this.system, { buildDir: this.rootDir, ...compilerOptions }); + this.compileAddons(compOptions.addons.getAddonDir()); + + this.compiler = new Compiler(compOptions, this.system); + + if (!this.system.directoryExists(this.rootDir)) { + this.system.createDirectory(this.rootDir); + } + } + + public getRootDir(): string { + return this.rootDir; + } + + public getCompiler(): Compiler { + return this.compiler; + } + public getCompilerOptions(): CompilerOptions { + return this.compiler.getOptions(); + } + + public getSystem(): ts.System { + return this.system; + } + public cleanUp(path?: string): this { + const target = path ?? this.rootDir; + if (this.system.fileExists(target)) { + this.system.readDirectory(target).forEach(it => this.system.deleteFile!(it)); + } + return this; + } + + public getAddons() { + return this.compiler.getOptions().addons; + } + + public addAddon(addonName: string, addonCode: string): this { + this.addAddonFile(addonName, addonCode); + this.compileAddons(this.getAddons().getAddonDir()); + this.getAddons().refresh(); + return this; + } + + public addAddons(addonNames: string[], templateFolder = "../test-data/addons/", addonsDir?: string): this { + const addonsDirPath = resolvePath(this.system, addonsDir ?? this.getAddons().getAddonDir()); + addonNames.forEach(addon => { + copyFolderSync(this.system, join(__dirname, templateFolder, addon), addonsDirPath); + }); + this.compiler.getOptions().addons.refresh(); + // @ts-expect-error - private method + this.compiler.createTargetContextsIfNecessary(); + + return this; + } + + public addProject(projectName: string, targetDir?: string, templateFolder = "../test-data/projects/"): this { + const target = targetDir ?? this.getCompilerOptions().buildDir; + copyFolderSync(this.system, join(__dirname, templateFolder, projectName), target); + return this; + // return resolvePath(system, `${target}/${projectName}`); + } + + public addSourceFile(fileName: string, content: string): this { + this.system.writeFile(resolvePath(this.system, "src", fileName), content); + return this; + } + + private addAddonFile(addonName: string, addonCode: string) { + this.system.writeFile(resolvePath(this.system, this.getAddons().getAddonDir(), addonName, "addon.ts"), addonCode); + } + + private compileAddons(addonsDir: string) { + const addonsToCompile = this.system + .readDirectory(addonsDir) + .filter(it => it.endsWith(".ts")) + .map(it => dirname(it)); + + addonsToCompile.forEach(curDir => { + const comp = new Compiler( + { + ...compileOptions(this.system, { + buildDir: curDir, + }), + tsconfig: { fileNames: this.system.readDirectory(curDir).filter(it => it.endsWith(".ts")), options: {}, errors: [] }, + }, + this.system + ); + const result = comp.compile(); + console.debug(`XXX`, result.emittedFiles); + }); + } + + private addFiles(files?: Record) { + if (!files) { + return; + } + Object.keys(files).forEach(file => { + this.system.writeFile(file, files[file]); + }); + } +} + +export type CompilationOptions = { + compilerOptions?: Partial; + files?: Record; + virtual?: boolean; +}; + +export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => { + // if (withDefaults && !existsSync(join(projectDir, "websmith.config.json"))) { + // writeFileSync( + // join(projectDir, "websmith.config.json"), + // JSON.stringify({ + // addonsDir: "./addons", + // }) + // ); + // } + + return new CompilationEnv(rootDir, options); +}; diff --git a/packages/testing/src/compilation/resolve-path.ts b/packages/testing/src/compilation/resolve-path.ts new file mode 100644 index 00000000..097bb210 --- /dev/null +++ b/packages/testing/src/compilation/resolve-path.ts @@ -0,0 +1,10 @@ +import { isAbsolute, join } from "path"; +import ts from "typescript"; + +export const resolvePath = (fs: ts.System, ...pathSegments: string[]) => { + let resolvedPath = join(...pathSegments); + if (!isAbsolute(resolvedPath)) { + resolvedPath = join(fs.getCurrentDirectory(), ...pathSegments); + } + return resolvedPath; +}; diff --git a/packages/testing/src/compile-options.ts b/packages/testing/src/compile-options.ts index 2a426232..7c3e9159 100644 --- a/packages/testing/src/compile-options.ts +++ b/packages/testing/src/compile-options.ts @@ -7,6 +7,7 @@ import { AddonRegistry, type CompilerOptions } from "@quatico/websmith-core"; import ts from "typescript"; import { ReporterMock } from "./ReporterMock"; +import { resolvePath } from "./compilation/resolve-path"; export const compileOptions = ( system: ts.System, @@ -14,9 +15,10 @@ export const compileOptions = ( overrides?: Partial & { tsconfig?: Partial; project?: Partial; targets?: string[] } ): CompilerOptions => { const reporter = new ReporterMock(system); + const buildDir: string = resolvePath(system, overrides?.buildDir ?? "./src"); return { - addons: new AddonRegistry({ addonsDir: "./addons", reporter, system }), - buildDir: "./src", + addons: new AddonRegistry({ addonsDir: resolvePath(system, buildDir, "./addons"), reporter, system }), + buildDir, reporter, debug: false, sourceMap: false, @@ -25,6 +27,6 @@ export const compileOptions = ( ...overrides, project: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.Latest, configFilePath: "./tsconfig.json", ...overrides?.project }, targets: overrides?.targets ?? [], - tsconfig: { options: {}, fileNames: system.readDirectory("./src"), errors: [], ...overrides?.tsconfig }, + tsconfig: { options: {}, fileNames: system.readDirectory(buildDir), errors: [], ...overrides?.tsconfig }, }; }; diff --git a/packages/testing/test/__setup__/fusion-fs.ts b/packages/testing/test/__setup__/fusion-fs.ts new file mode 100644 index 00000000..58134211 --- /dev/null +++ b/packages/testing/test/__setup__/fusion-fs.ts @@ -0,0 +1,190 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* + * --------------------------------------------------------------------------------------------- + * Copyright (c) Quatico Solutions AG. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + * --------------------------------------------------------------------------------------------- + */ +import type fs from "fs"; +import { + type MakeDirectoryOptions, + type ObjectEncodingOptions, + type PathLike, + type PathOrFileDescriptor, + type Stats, + type WatchFileOptions, +} from "fs"; +import { createFsFromVolume, vol } from "memfs"; +import type Dirent from "memfs/lib/Dirent"; +import type { TDataOut } from "memfs/lib/encoding"; +import type { IWatchOptions, StatWatcher, TCallback } from "memfs/lib/volume"; +import type { IReadStream } from "memfs/lib/node/types/misc"; +import type { IReadStreamOptions, IReaddirOptions } from "memfs/lib/node/types/options"; +import { dirname } from "path"; + +/** + * Creates a new fs module that uses the memfs volume as a base. + * This can be very useful for testing purposes. The actual fs module is used as a fallback. + * + * For example in your `jest.setup.js` file you can use this function to replace the fs module as follows: + * + * import { createFs, resetFs } from "@quatico/websmith-testing"; + * + * jest.mock("fs", () => { + * return createFs(jest.requireActual("fs")); + * }); + * + * afterEach(() => { + * jest.clearAllMocks(); + * resetFs(); + * }); + * + * + * @param actualFs + * @returns + */ + +export const createFs = (actualFs: typeof fs): typeof fs => { + const memfs = createFsFromVolume(vol); + + return { + ...actualFs, + readlink: ( + path: PathLike, + options: fs.BufferEncodingOption, + callback: (err: NodeJS.ErrnoException | null, linkString: Buffer) => void + ): void => { + return memfs.existsSync(path) ? memfs.readlink(path, options as any, callback as any) : actualFs.readlink(path, options, callback); + }, + readlinkSync: (path: PathLike, options?: fs.EncodingOption): string | Buffer => { + return memfs.existsSync(path) ? memfs.readlinkSync(path, options as any) : actualFs.readlinkSync(path, options); + }, + read: ( + fd: number, + buffer: TBuffer, + offset: number, + length: number, + position: fs.ReadPosition | null, + callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void + ): void => { + return memfs.fstatSync(fd) + ? memfs.read(fd, buffer as any, offset, length, position as any, callback as any) + : actualFs.read(fd, buffer, offset, length, position, callback); + }, + // readSync: (fd: number, buffer: NodeJS.ArrayBufferView, opts?: ReadSyncOptions): number => { + readSync: (fd: number, buffer: NodeJS.ArrayBufferView, offset: number, length: number, position: fs.ReadPosition | null): number => { + return memfs.fstatSync(fd) + ? memfs.readSync(fd, buffer as any, offset, length, position as any) + : actualFs.readSync(fd, buffer, offset, length, position); + }, + readFile: ( + path: PathLike, + options: IReaddirOptions | string, + callback: (err: NodeJS.ErrnoException | null, data: Buffer | string) => void + ): void => { + options = options ?? { encoding: "utf-8" }; + return memfs.existsSync(path) ? memfs.readFile(path, options, callback as any) : actualFs.readFile(path, options as any, callback); + }, + readFileSync: ( + path: PathOrFileDescriptor, + options?: BufferEncoding | (ObjectEncodingOptions & { flag?: string | undefined }) | null | undefined + ): string | Buffer => { + try { + const content = memfs.readFileSync(path, options as any); + if (content) { + return content; + } + } catch (err) { + // falls through + } + return actualFs.readFileSync(path, options); + }, + copyFileSync: (src: PathLike, dest: PathLike, mode?: number): void => { + if (memfs.existsSync(src)) { + memfs.copyFileSync(src, dest, mode); + } else { + const file = actualFs.readFileSync(src); + memfs.writeFileSync(dest, file); + } + }, + readdir: (path: PathLike, options: IReaddirOptions | string, callback: (err: NodeJS.ErrnoException | null, files: string[]) => void): any => { + options = options ?? { encoding: "utf-8" }; + return memfs.existsSync(path) ? memfs.readdir(path, options, callback as any) : actualFs.readdir(path, options as any, callback); + }, + readdirSync: ( + path: PathLike, + options?: + | { + encoding: BufferEncoding | null; + withFileTypes?: false | undefined; + } + | BufferEncoding + | null + ): TDataOut[] | Buffer[] | Dirent[] | string[] => { + options = options ?? { encoding: "utf-8" }; + return memfs.existsSync(path) ? memfs.readdirSync(path, options as any) : actualFs.readdirSync(path, options); + }, + writeFile: memfs.writeFile, + writeFileSync: (file: PathOrFileDescriptor, data: any, options?: any): void => { + const parent = dirname(file.toString()); + if (!memfs.existsSync(parent)) { + memfs.mkdirSync(parent, { recursive: true }); + } + memfs.writeFileSync(file, data, options ?? { encoding: "utf-8" }); + }, + writeSync: memfs.writeSync, + write: memfs.write, + mkdir: memfs.mkdir, + mkdirSync: ( + path: PathLike, + options: MakeDirectoryOptions & { + recursive: true; + } + ) => memfs.mkdirSync(path, options ?? { recursive: true }), + exists: (path: PathLike, callback: (exists: boolean) => void): void => + memfs.existsSync(path) ? memfs.exists(path, callback as any) : actualFs.exists(path, callback), + existsSync: (path: PathLike): boolean => memfs.existsSync(path) || actualFs.existsSync(path), + lstat: memfs.lstat, + lstatSync: (path: PathLike): Stats => (memfs.existsSync(path) ? memfs.lstatSync(path) : actualFs.lstatSync(path)), + fstat: memfs.fstat, + fstatSync: memfs.fstatSync, + stat: (path: PathLike, callback: TCallback): void => + memfs.existsSync(path) ? memfs.stat(path, callback as any) : actualFs.stat(path, callback), + statSync: (path: PathLike): Stats => (memfs.existsSync(path) ? memfs.statSync(path) : actualFs.statSync(path)), + createReadStream: (path: PathLike, options?: BufferEncoding | IReadStreamOptions): IReadStream | fs.ReadStream => + memfs.existsSync(path) ? memfs.createReadStream(path, options) : actualFs.createReadStream(path, options as any), + unlinkSync: memfs.unlinkSync, + realpathSync: (path: PathLike, options?: { encoding?: BufferEncoding | null } | BufferEncoding | null): string | TDataOut | Buffer => + memfs.existsSync(path) ? memfs.realpathSync(path, options as any) : actualFs.realpathSync(path, options), + openSync: (path: PathLike, flags: string | number, mode?: string | number): number => { + if (!memfs.existsSync(path) && actualFs.existsSync(path)) { + memfs.writeFileSync(path, actualFs.readFileSync(path)); + } else { + memfs.mkdirSync(dirname(path.toString()), { recursive: true }); + memfs.writeFileSync(path, ""); + } + return memfs.openSync(path, flags, mode); + }, + closeSync: memfs.closeSync, + watch: (path: PathLike, options?: IWatchOptions | string, listener?: (eventType: string, filename: string) => void) => + memfs.existsSync(path) ? memfs.watch(path, options, listener) : actualFs.watch(path, options as any, listener as any), + watchFile: ( + path: PathLike, + options: + | (WatchFileOptions & { + bigint: true; + }) + | undefined, + listener: (curr: Stats, prev: Stats) => void + ): StatWatcher => + memfs.existsSync(path) + ? (memfs.watchFile(path, options as any, listener as any) as any) + : actualFs.watchFile(path, options as any, listener), + unwatchFile: (path: PathLike, listener?: (curr: Stats, prev: Stats) => void): void => + memfs.existsSync(path) ? memfs.unwatchFile(path, listener as any) : actualFs.unwatchFile(path, listener), + } as any; +}; + +export const resetFs = (): void => { + vol.reset(); +}; diff --git a/packages/testing/test/__setup__/jest.setup.ts b/packages/testing/test/__setup__/jest.setup.ts new file mode 100644 index 00000000..0d029edd --- /dev/null +++ b/packages/testing/test/__setup__/jest.setup.ts @@ -0,0 +1,14 @@ +import { createFs, resetFs } from "./fusion-fs"; + +jest.mock("fs", () => { + return createFs(jest.requireActual("memfs")); +}); + +jest.mock("fs/promises", () => { + return createFs(jest.requireActual("memfs")); +}); + +afterEach(() => { + jest.clearAllMocks(); + resetFs(); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d9661f60..550e30aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -445,6 +445,9 @@ importers: '@quatico/websmith-core': specifier: workspace:^ version: link:../core + '@quatico/websmith-testing': + specifier: workspace:^ + version: link:../testing '@swc/core': specifier: 1.5.0 version: 1.5.0 @@ -533,6 +536,12 @@ importers: '@nx/eslint-plugin': specifier: ^18.3.3 version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + '@quatico/websmith-api': + specifier: ^0.5.3 + version: 0.5.3(typescript@5.4.5) + '@quatico/websmith-compiler': + specifier: ^0.5.3 + version: 0.5.3(@swc/core@1.5.0)(@types/node@20.12.7) '@swc/core': specifier: 1.5.0 version: 1.5.0 @@ -1748,6 +1757,20 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@quatico/websmith-api@0.5.3': + resolution: {integrity: sha512-ikaOGtvS4QS4nKnrCLnIAleQmDhLbeuVwa24EYJGBnhzv3yXmNQP4s/WmTY0PtbhecW2Chd3HvKBEU4INPvdKQ==} + peerDependencies: + typescript: 5.x + + '@quatico/websmith-compiler@0.5.3': + resolution: {integrity: sha512-tED7EHZHEh3HFi0vngDYFHY4TOtTAufQAVo4mUK8GSDSUd8GnL0FezX9+rFy10ZMzswadw9AiwtOZwnrb64KlQ==} + hasBin: true + + '@quatico/websmith-core@0.5.3': + resolution: {integrity: sha512-UAPo6uyrjaswhbZtFGaGW0PNyJjGK1AqjA9Sq9Fno4j6vVb7v8nEnN+GXCl6zh6BQnoY8syzPFcdQt92BhkCOg==} + peerDependencies: + typescript: 5.x + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -5917,6 +5940,32 @@ snapshots: '@protobufjs/utf8@1.1.0': {} + '@quatico/websmith-api@0.5.3(typescript@5.4.5)': + dependencies: + typescript: 5.4.5 + + '@quatico/websmith-compiler@0.5.3(@swc/core@1.5.0)(@types/node@20.12.7)': + dependencies: + '@quatico/websmith-api': 0.5.3(typescript@5.4.5) + '@quatico/websmith-core': 0.5.3(typescript@5.4.5) + commander: 12.0.0 + minimist: 1.2.8 + ts-node: 10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5) + tslib: 2.6.2 + typescript: 5.4.5 + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + + '@quatico/websmith-core@0.5.3(typescript@5.4.5)': + dependencies: + '@quatico/websmith-api': 0.5.3(typescript@5.4.5) + create-hash: 1.2.0 + lodash: 4.17.21 + path: 0.12.7 + typescript: 5.4.5 + '@sinclair/typebox@0.27.8': {} '@sinonjs/commons@3.0.1': From 52e92c0511dbd81c084e81b31487986fb222c5d6 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Mon, 29 Apr 2024 21:19:33 +0200 Subject: [PATCH 03/52] !! Makes project compile --- packages/test/src/setup/environment.ts | 8 ++-- .../test/src/test-examples/bar-addon.test.ts | 8 ++-- packages/testing/jest.config.js | 1 - packages/testing/package.json | 4 +- .../testing/src/compilation/environment.ts | 3 +- pnpm-lock.yaml | 46 ------------------- 6 files changed, 10 insertions(+), 60 deletions(-) diff --git a/packages/test/src/setup/environment.ts b/packages/test/src/setup/environment.ts index a5836519..5466d6e4 100644 --- a/packages/test/src/setup/environment.ts +++ b/packages/test/src/setup/environment.ts @@ -14,7 +14,7 @@ export interface WebsmithEnv { system: ts.System; cleanUp: (path?: string) => void; addAddons: (addonNames: string, templateFolder?: string, addonsDir?: string) => AddonRegistry; - setProject: (projectName: string, targetDir?: string, templateFolder?: string) => string; + addProject: (projectName: string, targetDir?: string, templateFolder?: string) => string; sourceFile: (fileName: string, content: string) => string; } @@ -122,7 +122,7 @@ export const setUp = (rootDir: string, options?: WebsmithOptions): WebsmithEnv = } }; - const installAddons = ( + const addAddons = ( addonNames: string, templateFolder = "../test-data/addons/", addonsDir = compileOptions.addons.getAddonDir() @@ -138,7 +138,7 @@ export const setUp = (rootDir: string, options?: WebsmithOptions): WebsmithEnv = return registry; }; - const installProject = (projectName: string, targetDir?: string, templateFolder = "../test-data/projects/"): string => { + const addProject = (projectName: string, targetDir?: string, templateFolder = "../test-data/projects/"): string => { const target = targetDir ?? process.cwd(); copyFolderSync(system, join(__dirname, templateFolder, projectName), target); return resolvePath(system, `${target}/${projectName}`); @@ -156,6 +156,6 @@ export const setUp = (rootDir: string, options?: WebsmithOptions): WebsmithEnv = cleanUp, addAddons, sourceFile, - setProject, + addProject, }; }; diff --git a/packages/test/src/test-examples/bar-addon.test.ts b/packages/test/src/test-examples/bar-addon.test.ts index 1af1c69b..219a8a70 100644 --- a/packages/test/src/test-examples/bar-addon.test.ts +++ b/packages/test/src/test-examples/bar-addon.test.ts @@ -1,6 +1,6 @@ import { activeAddons, execute, fileContent, pathExists, setUp } from "../setup"; -const { rootDir, cleanUp, compiler, addAddons, setProject, system } = setUp("__TEMP__"); +const { rootDir, cleanUp, compiler, addAddons, addProject, system } = setUp("__TEMP__"); beforeAll(() => { addAddons("foo-addon", "../test-data/addons/"); @@ -13,7 +13,7 @@ afterAll(() => { describe("test-project-foo", () => { let projectDir: string; beforeEach(() => { - projectDir = setProject("test-project-foo", rootDir, "../test-data/projects/"); + projectDir = addProject("test-project-foo", rootDir, "../test-data/projects/"); }); afterEach(() => { @@ -49,7 +49,7 @@ describe("test-project-foo", () => { describe("test-project-foobar", () => { beforeEach(() => { - setProject("test-project-foobar"); + addProject("test-project-foobar"); }); afterEach(() => { @@ -78,7 +78,7 @@ describe("test-project-foobar", () => { describe("test-project-one", () => { let projectDir: string; beforeEach(() => { - projectDir = setProject("test-project-one", rootDir, "../test-data/projects/"); + projectDir = addProject("test-project-one", rootDir, "../test-data/projects/"); }); afterEach(() => { diff --git a/packages/testing/jest.config.js b/packages/testing/jest.config.js index ef5df41d..05d0e9c7 100644 --- a/packages/testing/jest.config.js +++ b/packages/testing/jest.config.js @@ -12,7 +12,6 @@ module.exports = { coveragePathIgnorePatterns: ["index.ts"], moduleFileExtensions: ["ts", "js", "json", "node"], moduleNameMapper: { - "@quatico/websmith-api": "/../api/src", "@quatico/websmith-core": "/../core/src", }, prettierPath: null, diff --git a/packages/testing/package.json b/packages/testing/package.json index 90a2e958..89e3d313 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -32,9 +32,7 @@ "dist": "pnpm clean && pnpm lint && pnpm test && cross-env-shell NODE_ENV=production \"pnpm build\"" }, "dependencies": { - "@quatico/websmith-core": "workspace:^", - "@quatico/websmith-api": "workspace:^", - "@quatico/websmith-compiler": "workspace:^" + "@quatico/websmith-core": "workspace:^" }, "devDependencies": { "@eslint/js": "^9.1.1", diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 288ae22a..f6dbef4a 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -12,7 +12,7 @@ export class CompilationEnv { private system: ts.System; constructor(rootDir: string, options?: CompilationOptions) { - const { virtual = true, compilerOptions = {}, files } = options ?? {}; + const { compilerOptions = {}, files } = options ?? {}; this.system = ts.sys; this.rootDir = resolvePath(this.system, rootDir); @@ -123,7 +123,6 @@ export class CompilationEnv { export type CompilationOptions = { compilerOptions?: Partial; files?: Record; - virtual?: boolean; }; export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 550e30aa..9e715236 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -536,12 +536,6 @@ importers: '@nx/eslint-plugin': specifier: ^18.3.3 version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) - '@quatico/websmith-api': - specifier: ^0.5.3 - version: 0.5.3(typescript@5.4.5) - '@quatico/websmith-compiler': - specifier: ^0.5.3 - version: 0.5.3(@swc/core@1.5.0)(@types/node@20.12.7) '@swc/core': specifier: 1.5.0 version: 1.5.0 @@ -1757,20 +1751,6 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - '@quatico/websmith-api@0.5.3': - resolution: {integrity: sha512-ikaOGtvS4QS4nKnrCLnIAleQmDhLbeuVwa24EYJGBnhzv3yXmNQP4s/WmTY0PtbhecW2Chd3HvKBEU4INPvdKQ==} - peerDependencies: - typescript: 5.x - - '@quatico/websmith-compiler@0.5.3': - resolution: {integrity: sha512-tED7EHZHEh3HFi0vngDYFHY4TOtTAufQAVo4mUK8GSDSUd8GnL0FezX9+rFy10ZMzswadw9AiwtOZwnrb64KlQ==} - hasBin: true - - '@quatico/websmith-core@0.5.3': - resolution: {integrity: sha512-UAPo6uyrjaswhbZtFGaGW0PNyJjGK1AqjA9Sq9Fno4j6vVb7v8nEnN+GXCl6zh6BQnoY8syzPFcdQt92BhkCOg==} - peerDependencies: - typescript: 5.x - '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -5940,32 +5920,6 @@ snapshots: '@protobufjs/utf8@1.1.0': {} - '@quatico/websmith-api@0.5.3(typescript@5.4.5)': - dependencies: - typescript: 5.4.5 - - '@quatico/websmith-compiler@0.5.3(@swc/core@1.5.0)(@types/node@20.12.7)': - dependencies: - '@quatico/websmith-api': 0.5.3(typescript@5.4.5) - '@quatico/websmith-core': 0.5.3(typescript@5.4.5) - commander: 12.0.0 - minimist: 1.2.8 - ts-node: 10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5) - tslib: 2.6.2 - typescript: 5.4.5 - transitivePeerDependencies: - - '@swc/core' - - '@swc/wasm' - - '@types/node' - - '@quatico/websmith-core@0.5.3(typescript@5.4.5)': - dependencies: - '@quatico/websmith-api': 0.5.3(typescript@5.4.5) - create-hash: 1.2.0 - lodash: 4.17.21 - path: 0.12.7 - typescript: 5.4.5 - '@sinclair/typebox@0.27.8': {} '@sinonjs/commons@3.0.1': From 3900465624845ea14ca9dd6a9b488900cffecb52 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Mon, 29 Apr 2024 23:41:34 +0200 Subject: [PATCH 04/52] F Provides intial testing API for websmith addons + Support for virtual mode (everything in memory, no FS needed) + Add addons to the compilation from existing directory or from source string + Add project code to the compilation from existing directory or from source string + Remove need for fusion-fs in addon tests --- packages/test/src/setup/environment.spec.ts | 23 --- packages/test/src/setup/environment.ts | 161 --------------- packages/test/src/setup/index.ts | 1 - packages/testing/jest.config.js | 2 +- packages/testing/package.json | 4 +- packages/testing/src/compilation/copy.ts | 7 +- .../src/compilation/environment.spec.ts | 194 ++++++++++++++++-- .../testing/src/compilation/environment.ts | 85 ++++++-- packages/testing/test/__setup__/fusion-fs.ts | 190 ----------------- packages/testing/test/__setup__/jest.setup.ts | 14 -- pnpm-lock.yaml | 18 ++ 11 files changed, 271 insertions(+), 428 deletions(-) delete mode 100644 packages/test/src/setup/environment.spec.ts delete mode 100644 packages/test/src/setup/environment.ts delete mode 100644 packages/testing/test/__setup__/fusion-fs.ts delete mode 100644 packages/testing/test/__setup__/jest.setup.ts diff --git a/packages/test/src/setup/environment.spec.ts b/packages/test/src/setup/environment.spec.ts deleted file mode 100644 index ed0f0dcd..00000000 --- a/packages/test/src/setup/environment.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { setUp } from "./environment"; -import { activeAddons } from "./expect"; - -describe("installAddons", () => { - it("should install addon successfully", () => { - const { addAddons, cleanUp, rootDir } = setUp("/", { - virtual: true, - files: { - "/addons/tsconfig.json": "{}", - "./addons/target-addon/addon.ts": ` - export const activate = () => {}; - `, - "./tsconfig.json": "{}", - }, - }); - - const actual = addAddons("target-addon", "../test-data/addons/"); - - cleanUp(rootDir); - - expect(activeAddons(actual)).toEqual(["target-addon"]); - }); -}); diff --git a/packages/test/src/setup/environment.ts b/packages/test/src/setup/environment.ts deleted file mode 100644 index 5466d6e4..00000000 --- a/packages/test/src/setup/environment.ts +++ /dev/null @@ -1,161 +0,0 @@ -import type { Reporter } from "@quatico/websmith-api"; -import { CompilerArguments, createOptions } from "@quatico/websmith-compiler"; -import { AddonRegistry, Compiler, createBrowserSystem } from "@quatico/websmith-core"; -import { dirname, join } from "path"; -import ts from "typescript"; -import { copyFolderSync } from "./copy"; -import { fileContent } from "./expect"; -import { resolvePath } from "./paths"; -import { stringToArray } from "./values"; - -export interface WebsmithEnv { - compiler: Compiler; - rootDir: string; - system: ts.System; - cleanUp: (path?: string) => void; - addAddons: (addonNames: string, templateFolder?: string, addonsDir?: string) => AddonRegistry; - addProject: (projectName: string, targetDir?: string, templateFolder?: string) => string; - sourceFile: (fileName: string, content: string) => string; -} - -export type WebsmithOptions = { - compilerArguments?: CompilerArguments; - files?: Record; - reporter?: Reporter; - useCaseSensitiveFileNames?: boolean; - virtual?: boolean; -}; - -export const setUp = (rootDir: string, options?: WebsmithOptions): WebsmithEnv => { - const { virtual = false, compilerArguments = {}, useCaseSensitiveFileNames, files, reporter } = options ?? {}; - - const system = virtual ? createBrowserSystem(files, useCaseSensitiveFileNames) : ts.sys; - - if (files) { - if (!virtual) { - throw new Error("Cannot provide files in non-virtual mode."); - } - - const addonsToCompile = Object.keys(files) - .filter(it => it.endsWith("/addon.ts")) - .map(it => dirname(it)); - addonsToCompile.forEach(curDir => { - const addonCompiler = new Compiler( - { - ...createOptions( - { - addons: "", - addonsDir: "./do-not-use-addons", - buildDir: curDir, - }, - reporter, - system - ), - project: { module: ts.ModuleKind.ES2015, target: ts.ScriptTarget.ES5 }, - tsconfig: { options: {}, fileNames: system.readDirectory(curDir).filter(it => it.endsWith(".ts")), errors: [] }, - }, - system - ); - addonCompiler.compile(); - }); - - if (!fileContent(system, "./addons/target-addon/addon.js", "/")) { - throw new Error(`Addons not compiled. ${system.readDirectory("./addons")}`); - } - - jest.mock( - "/addons/target-addon/addon", - () => { - return eval(files["./addons/target-addon/addon.js"]); - }, - { virtual: true } - ); - } - - const compileOptions = createOptions({ buildDir: "/", project: "./tsconfig.json", ...compilerArguments }, reporter, system); - const resolved = resolvePath(system, rootDir); - const compiler = new Compiler(compileOptions, system); - - if (!system.directoryExists(resolved)) { - system.createDirectory(resolved); - } - - process.chdir(resolved); - - // if (withDefaults && !existsSync(join(projectDir, "src"))) { - // mkdirSync(join(projectDir, "src")); - // } - // process.chdir(projectDir); - - // if (withDefaults && !existsSync(join(projectDir, "websmith.config.json"))) { - // writeFileSync( - // join(projectDir, "websmith.config.json"), - // JSON.stringify({ - // addonsDir: "./addons", - // }) - // ); - // } - - // if (withDefaults && !existsSync(join(projectDir, "tsconfig.json"))) { - // writeFileSync( - // join(projectDir, "tsconfig.json"), - // JSON.stringify({ - // compilerOptions: { - // target: "ESNEXT", - // module: "ESNEXT", - // lib: ["es2017", "es7", "es6", "dom"], - // declaration: true, - // outDir: "dist", - // strict: true, - // esModuleInterop: true, - // }, - // include: ["src"], - // exclude: ["node_modules", "dist"], - // }) - // ); - // } - - const cleanUp = (path?: string): void => { - const target = path ?? resolved; - if (system.fileExists(target)) { - system.readDirectory(target).forEach(it => system.deleteFile!(it)); - } - }; - - const addAddons = ( - addonNames: string, - templateFolder = "../test-data/addons/", - addonsDir = compileOptions.addons.getAddonDir() - ): AddonRegistry => { - const addonsDirPath = resolvePath(system, addonsDir); - stringToArray(addonNames).forEach(addon => { - copyFolderSync(system, join(__dirname, templateFolder, addon), addonsDirPath); - }); - const registry = compileOptions.addons.refresh(); - // @ts-expect-error - private method - compiler.createTargetContextsIfNecessary(); - - return registry; - }; - - const addProject = (projectName: string, targetDir?: string, templateFolder = "../test-data/projects/"): string => { - const target = targetDir ?? process.cwd(); - copyFolderSync(system, join(__dirname, templateFolder, projectName), target); - return resolvePath(system, `${target}/${projectName}`); - }; - - const sourceFile = (fileName: string, content: string): string => { - system.writeFile(resolvePath(system, "src", fileName), content); - return content; - }; - - return { - rootDir: resolved, - compiler, - system, - cleanUp, - addAddons, - sourceFile, - addProject, - }; -}; diff --git a/packages/test/src/setup/index.ts b/packages/test/src/setup/index.ts index b0081c31..90444cab 100644 --- a/packages/test/src/setup/index.ts +++ b/packages/test/src/setup/index.ts @@ -2,6 +2,5 @@ export * from "./config"; export * from "./copy"; export * from "./execute"; export * from "./expect"; -export * from "./environment"; export * from "./paths"; export * from "./values"; diff --git a/packages/testing/jest.config.js b/packages/testing/jest.config.js index 05d0e9c7..85ec29b4 100644 --- a/packages/testing/jest.config.js +++ b/packages/testing/jest.config.js @@ -16,7 +16,7 @@ module.exports = { }, prettierPath: null, testRegex: "src/.*spec\\.(js|ts)$", - setupFilesAfterEnv: ["/test/__setup__/jest.setup.ts", "/../../jest.setup.ts"], + setupFilesAfterEnv: ["/../../jest.setup.ts"], testEnvironmentOptions: { url: "http://localhost/" }, transform: { "^.+\\.(js|ts)$": [ diff --git a/packages/testing/package.json b/packages/testing/package.json index 89e3d313..8d068be1 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -32,7 +32,8 @@ "dist": "pnpm clean && pnpm lint && pnpm test && cross-env-shell NODE_ENV=production \"pnpm build\"" }, "dependencies": { - "@quatico/websmith-core": "workspace:^" + "@quatico/websmith-core": "workspace:^", + "require-from-string": "^2.0.2" }, "devDependencies": { "@eslint/js": "^9.1.1", @@ -40,6 +41,7 @@ "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", + "@types/require-from-string": "^1.2.3", "concurrently": "^8.2.2", "cross-env": "7.0.3", "eslint": "^9.1.1", diff --git a/packages/testing/src/compilation/copy.ts b/packages/testing/src/compilation/copy.ts index 33e8732f..55809dc1 100644 --- a/packages/testing/src/compilation/copy.ts +++ b/packages/testing/src/compilation/copy.ts @@ -24,11 +24,10 @@ export const copyFolderSync = (system: ts.System, source: string, target: string if (system.directoryExists(source)) { files = system.readDirectory(source); files.forEach(file => { - const curSource = join(source, file); - if (system.directoryExists(curSource)) { - copyFolderSync(system, curSource, targetFolder); + if (system.directoryExists(file)) { + copyFolderSync(system, file, targetFolder); } else { - copyFileSync(system, curSource, targetFolder); + copyFileSync(system, file, targetFolder); } }); } diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index 35512821..b912895b 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -1,28 +1,34 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ import ts from "typescript"; import { compilationEnv, type CompilationEnv } from "./environment"; -describe("compilationEnv", () => { - let testObj: CompilationEnv; +let testObj: CompilationEnv; +describe("compilationEnv", () => { afterEach(() => { testObj.cleanUp(); }); - it("should return a new compilation environment with defaults", () => { + it("should yield default configuration with defaults", () => { testObj = compilationEnv("expected"); expect(testObj.getRootDir().endsWith("/expected")).toBe(true); expect(testObj.getCompiler()).toBeDefined(); - expect(testObj.getSystem()).toBe(ts.sys); + expect(testObj.isVirtual()).toBe(true); + expect(testObj.getSystem()).toBeDefined(); + expect(testObj.getSystem().useCaseSensitiveFileNames).toBe(false); }); - it("should return a new compilation environment with default compiler options", () => { + it("should yield default compiler options with defaults", () => { testObj = compilationEnv("/target"); const actual = testObj.getCompilerOptions(); expect(actual).toMatchObject({ - buildDir: "/", + buildDir: "/target", project: { configFilePath: "./tsconfig.json", module: ts.ModuleKind.ESNext, @@ -39,7 +45,7 @@ describe("compilationEnv", () => { }); }); - it("should return a new compilation environment with custom compiler options", () => { + it("should yield custom compiler options with custom overrides", () => { testObj = compilationEnv("/target", { compilerOptions: { buildDir: "/expected-src", project: { outDir: "/expected-out" } } }); const actual = testObj.getCompilerOptions(); @@ -54,30 +60,190 @@ describe("compilationEnv", () => { }, }); }); +}); - it("should return a new compilation environment with default addons", () => { +describe("compilationEnv#addons", () => { + afterEach(() => { + testObj.cleanUp(); + }); + + it("should yields no addons with defaults", () => { testObj = compilationEnv("/target"); const actual = testObj.getAddons(); - expect(actual.getAddonDir()).toBe("./addons"); + expect(actual.getAddonDir()).toBe("/target/addons"); expect(actual.getAvailableAddons()).toEqual([]); }); - it("should return a new compilation environment with valid custom addons", () => { + it("should yield addon with valid addon source", () => { testObj = compilationEnv("/target").addAddon("expected-addon", `export const activate = () => {};`); - const actual = testObj.getAddons().getAvailableAddons(); + const actual = testObj + .getAddons() + .getAvailableAddons() + .map(it => it?.name); - expect(testObj.getSystem().readDirectory("/target")).toEqual(["/addons/expected-addon/addon.ts"]); expect(actual).toEqual(["expected-addon"]); }); - it("should return a new compilation environment with valid custom addonsXXX", () => { - testObj = compilationEnv("/target").addAddon("expected-addon", `export const activate = () => {};`); + it("should yield no addons with invalid addon source", () => { + testObj = compilationEnv("/target").addAddon("invalid-addon", `export const NO_ACTIVATE_FUNCTION = true;`); const actual = testObj.getAddons().getAvailableAddons(); + expect(actual).toHaveLength(0); + }); + + it("should yield addon with single addon in default addons path", () => { + testObj = compilationEnv("/target"); + testObj.getSystem().writeFile("/test-data/addons/expected-addon/addon.ts", `export const activate = () => {};`); + + testObj.addAddons(["expected-addon"]); + + const actual = testObj + .getAddons() + .getAvailableAddons() + .map(it => it?.name); + expect(actual).toEqual(["expected-addon"]); }); + + it("should yield addons with multiple addons in default addons path", () => { + testObj = compilationEnv("/target"); + testObj.getSystem().writeFile("/test-data/addons/expected-addon1/addon.ts", `export const activate = () => {};`); + testObj.getSystem().writeFile("/test-data/addons/expected-addon2/addon.ts", `export const activate = () => {};`); + + testObj.addAddons(["expected-addon1", "expected-addon2"]); + + const actual = testObj + .getAddons() + .getAvailableAddons() + .map(it => it?.name); + + expect(actual).toEqual(["expected-addon1", "expected-addon2"]); + }); + + it("should yield addons with multiple addons in custom addons path", () => { + testObj = compilationEnv("/target"); + testObj.getSystem().writeFile("/target/custom-addons-folder/expected-addon1/addon.ts", `export const activate = () => {};`); + testObj.getSystem().writeFile("/target/custom-addons-folder/expected-addon2/addon.ts", `export const activate = () => {};`); + + testObj.addAddons(["expected-addon1", "expected-addon2"], "./custom-addons-folder/"); + + const actual = testObj + .getAddons() + .getAvailableAddons() + .map(it => it?.name); + + expect(actual).toEqual(["expected-addon1", "expected-addon2"]); + }); +}); + +describe("compilationEnv#projects", () => { + it("should yield no projects with defaults", () => { + testObj = compilationEnv("/target").addProject("expected-project"); + + const actual = testObj.getProjects(); + + expect(actual).toHaveLength(0); + }); + + it("should yield project with project files and file names", () => { + testObj = compilationEnv("/target"); + testObj.addProject("expected-project", { projectFiles: { "index.ts": `export * from "./target";`, "target.ts": `export class Target {}` } }); + + const actual = testObj.getProjects(); + + expect(actual).toEqual(["/target/expected-project"]); + }); + + it("should yield project with project files and relative paths", () => { + testObj = compilationEnv("/target"); + testObj.addProject("expected-project", { + projectFiles: { "./foo-bar/index.ts": `export * from "./target";`, "./foo-bar/target.ts": `export class Target {}` }, + }); + + const actual = testObj.getProjects(); + + expect(actual).toEqual(["/target/expected-project"]); + }); + + it("should yield project with project files and relative project paths", () => { + testObj = compilationEnv("/target"); + testObj.addProject("expected-project", { + projectFiles: { "./expected-project/index.ts": `export * from "./target";`, "./expected-project/target.ts": `export class Target {}` }, + }); + + const actual = testObj.getProjects(); + + expect(actual).toEqual(["/target/expected-project"]); + }); + + it("should yield project with project files and absolute paths", () => { + testObj = compilationEnv("/target"); + testObj.addProject("expected-project", { + projectFiles: { + "/target/expected-project/index.ts": `export * from "./target";`, + "/target/expected-project/target.ts": `export class Target {}`, + }, + }); + + const actual = testObj.getProjects(); + + expect(actual).toEqual(["/target/expected-project"]); + }); + + it("should yield no projects with project files and invalid absolute paths", () => { + testObj = compilationEnv("/target"); + testObj.addProject("expected-project", { + projectFiles: { + // buildDir is missing in absolute paths + "/expected-project/index.ts": `export * from "./target";`, + "/expected-project/target.ts": `export class Target {}`, + }, + }); + + const actual = testObj.getProjects(); + + expect(actual).toHaveLength(0); + }); + + it("should yield project with single project in default projects path", () => { + testObj = compilationEnv("/target"); + testObj.getSystem().writeFile("/test-data/projects/expected-project/index.ts", `export * from "./target";`); + testObj.getSystem().writeFile("/test-data/projects/expected-project/target.ts", `export class Target {}`); + + testObj.addProject("expected-project"); + + const actual = testObj.getProjects(); + + expect(actual).toEqual(["/target/expected-project"]); + }); + + it("should yield projects with multiple projects in default projects path", () => { + testObj = compilationEnv("/target"); + testObj.getSystem().writeFile("/test-data/projects/expected-project1/index.ts", `export * from "./one";`); + testObj.getSystem().writeFile("/test-data/projects/expected-project1/one.ts", `export class One {}`); + testObj.getSystem().writeFile("/test-data/projects/expected-project2/index.ts", `export * from "./two";`); + testObj.getSystem().writeFile("/test-data/projects/expected-project2/two.ts", `export class Two {}`); + + testObj.addProject("expected-project1").addProject("expected-project2"); + + const actual = testObj.getProjects(); + + expect(actual).toEqual(["/target/expected-project1", "/target/expected-project2"]); + }); + + it("should yield project with single project in custom projects path", () => { + testObj = compilationEnv("/target"); + testObj.getSystem().writeFile("/custom-projects/expected-project/index.ts", `export * from "./target";`); + testObj.getSystem().writeFile("/custom-projects/expected-project/target.ts", `export class Target {}`); + + testObj.addProject("expected-project", { sourceDir: "../custom-projects/" }); + + const actual = testObj.getProjects(); + + expect(actual).toEqual(["/target/expected-project"]); + }); }); diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index f6dbef4a..80bc7ba9 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -1,19 +1,21 @@ -import { Compiler, CompilerOptions } from "@quatico/websmith-core"; -import { dirname, join } from "path"; +import { Compiler, CompilerOptions, createBrowserSystem } from "@quatico/websmith-core"; +import { basename, dirname, extname, isAbsolute } from "path"; +import requireFromString from "require-from-string"; import ts from "typescript"; import { compileOptions } from "../compile-options"; import { copyFolderSync } from "./copy"; import { resolvePath } from "./resolve-path"; -// import fs from "memfs"; export class CompilationEnv { private compiler: Compiler; private rootDir: string; private system: ts.System; + private virtual: boolean; constructor(rootDir: string, options?: CompilationOptions) { - const { compilerOptions = {}, files } = options ?? {}; - this.system = ts.sys; + const { virtual = true, compilerOptions = {}, useCaseSensitiveFileNames, files } = options ?? {}; + this.virtual = virtual; + this.system = this.virtual ? createBrowserSystem(files, useCaseSensitiveFileNames) : ts.sys; this.rootDir = resolvePath(this.system, rootDir); this.addFiles(files); @@ -42,6 +44,11 @@ export class CompilationEnv { public getSystem(): ts.System { return this.system; } + + public isVirtual(): boolean { + return this.virtual; + } + public cleanUp(path?: string): this { const target = path ?? this.rootDir; if (this.system.fileExists(target)) { @@ -61,23 +68,48 @@ export class CompilationEnv { return this; } - public addAddons(addonNames: string[], templateFolder = "../test-data/addons/", addonsDir?: string): this { - const addonsDirPath = resolvePath(this.system, addonsDir ?? this.getAddons().getAddonDir()); + public addAddons(addonNames: string[], sourceDir = "../test-data/addons/"): this { + const addonsDir = resolvePath(this.system, this.getAddons().getAddonDir()); addonNames.forEach(addon => { - copyFolderSync(this.system, join(__dirname, templateFolder, addon), addonsDirPath); + copyFolderSync(this.system, resolvePath(this.system, this.rootDir, sourceDir, addon), addonsDir); }); - this.compiler.getOptions().addons.refresh(); - // @ts-expect-error - private method - this.compiler.createTargetContextsIfNecessary(); + this.compileAddons(this.getAddons().getAddonDir()); + this.getAddons().refresh(); return this; } - public addProject(projectName: string, targetDir?: string, templateFolder = "../test-data/projects/"): this { - const target = targetDir ?? this.getCompilerOptions().buildDir; - copyFolderSync(this.system, join(__dirname, templateFolder, projectName), target); + public getProjects(): string[] { + const buildDir = this.getCompilerOptions().buildDir; + const projectDirs = this.system.readDirectory(buildDir).map(it => { + const end = it.indexOf("/", buildDir.length + 1); + return it.substring(0, end); + }); + return [...new Set(projectDirs)]; + } + + public addProject(projectName: string, options?: { sourceDir?: string; projectFiles?: Record }): this { + const { sourceDir = "../test-data/projects/", projectFiles } = options ?? {}; + if (projectFiles) { + this.addFiles( + Object.entries(projectFiles).reduce((acc: Record, [filePath, content]) => { + if (isAbsolute(filePath)) { + acc[filePath] = content; + } else { + if (filePath.includes(projectName)) { + acc[resolvePath(this.system, this.rootDir, filePath)] = content; + } else { + acc[resolvePath(this.system, this.rootDir, projectName, filePath)] = content; + } + } + return acc; + }, {}) + ); + } else { + const projectDir = resolvePath(this.system, this.rootDir, sourceDir, projectName); + copyFolderSync(this.system, projectDir, this.getCompilerOptions().buildDir); + } return this; - // return resolvePath(system, `${target}/${projectName}`); } public addSourceFile(fileName: string, content: string): this { @@ -96,18 +128,31 @@ export class CompilationEnv { .map(it => dirname(it)); addonsToCompile.forEach(curDir => { - const comp = new Compiler( + new Compiler( { ...compileOptions(this.system, { buildDir: curDir, }), + project: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES5 }, tsconfig: { fileNames: this.system.readDirectory(curDir).filter(it => it.endsWith(".ts")), options: {}, errors: [] }, }, this.system - ); - const result = comp.compile(); - console.debug(`XXX`, result.emittedFiles); + ).compile(); }); + + if (this.virtual) { + this.system + .readDirectory(addonsDir, [".js", ".jsx"]) + .filter(it => basename(it, extname(it)).toLocaleLowerCase() === "addon") + .map(it => this.system.resolvePath(it)) + .forEach(it => { + jest.mock( + extname(it).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) ? it.replace(extname(it), "") : it, + () => requireFromString(this.system.readFile(it)!), + { virtual: true } + ); + }); + } } private addFiles(files?: Record) { @@ -123,6 +168,8 @@ export class CompilationEnv { export type CompilationOptions = { compilerOptions?: Partial; files?: Record; + useCaseSensitiveFileNames?: boolean; + virtual?: boolean; }; export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => { diff --git a/packages/testing/test/__setup__/fusion-fs.ts b/packages/testing/test/__setup__/fusion-fs.ts deleted file mode 100644 index 58134211..00000000 --- a/packages/testing/test/__setup__/fusion-fs.ts +++ /dev/null @@ -1,190 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* - * --------------------------------------------------------------------------------------------- - * Copyright (c) Quatico Solutions AG. All rights reserved. - * Licensed under the MIT License. See LICENSE in the project root for license information. - * --------------------------------------------------------------------------------------------- - */ -import type fs from "fs"; -import { - type MakeDirectoryOptions, - type ObjectEncodingOptions, - type PathLike, - type PathOrFileDescriptor, - type Stats, - type WatchFileOptions, -} from "fs"; -import { createFsFromVolume, vol } from "memfs"; -import type Dirent from "memfs/lib/Dirent"; -import type { TDataOut } from "memfs/lib/encoding"; -import type { IWatchOptions, StatWatcher, TCallback } from "memfs/lib/volume"; -import type { IReadStream } from "memfs/lib/node/types/misc"; -import type { IReadStreamOptions, IReaddirOptions } from "memfs/lib/node/types/options"; -import { dirname } from "path"; - -/** - * Creates a new fs module that uses the memfs volume as a base. - * This can be very useful for testing purposes. The actual fs module is used as a fallback. - * - * For example in your `jest.setup.js` file you can use this function to replace the fs module as follows: - * - * import { createFs, resetFs } from "@quatico/websmith-testing"; - * - * jest.mock("fs", () => { - * return createFs(jest.requireActual("fs")); - * }); - * - * afterEach(() => { - * jest.clearAllMocks(); - * resetFs(); - * }); - * - * - * @param actualFs - * @returns - */ - -export const createFs = (actualFs: typeof fs): typeof fs => { - const memfs = createFsFromVolume(vol); - - return { - ...actualFs, - readlink: ( - path: PathLike, - options: fs.BufferEncodingOption, - callback: (err: NodeJS.ErrnoException | null, linkString: Buffer) => void - ): void => { - return memfs.existsSync(path) ? memfs.readlink(path, options as any, callback as any) : actualFs.readlink(path, options, callback); - }, - readlinkSync: (path: PathLike, options?: fs.EncodingOption): string | Buffer => { - return memfs.existsSync(path) ? memfs.readlinkSync(path, options as any) : actualFs.readlinkSync(path, options); - }, - read: ( - fd: number, - buffer: TBuffer, - offset: number, - length: number, - position: fs.ReadPosition | null, - callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void - ): void => { - return memfs.fstatSync(fd) - ? memfs.read(fd, buffer as any, offset, length, position as any, callback as any) - : actualFs.read(fd, buffer, offset, length, position, callback); - }, - // readSync: (fd: number, buffer: NodeJS.ArrayBufferView, opts?: ReadSyncOptions): number => { - readSync: (fd: number, buffer: NodeJS.ArrayBufferView, offset: number, length: number, position: fs.ReadPosition | null): number => { - return memfs.fstatSync(fd) - ? memfs.readSync(fd, buffer as any, offset, length, position as any) - : actualFs.readSync(fd, buffer, offset, length, position); - }, - readFile: ( - path: PathLike, - options: IReaddirOptions | string, - callback: (err: NodeJS.ErrnoException | null, data: Buffer | string) => void - ): void => { - options = options ?? { encoding: "utf-8" }; - return memfs.existsSync(path) ? memfs.readFile(path, options, callback as any) : actualFs.readFile(path, options as any, callback); - }, - readFileSync: ( - path: PathOrFileDescriptor, - options?: BufferEncoding | (ObjectEncodingOptions & { flag?: string | undefined }) | null | undefined - ): string | Buffer => { - try { - const content = memfs.readFileSync(path, options as any); - if (content) { - return content; - } - } catch (err) { - // falls through - } - return actualFs.readFileSync(path, options); - }, - copyFileSync: (src: PathLike, dest: PathLike, mode?: number): void => { - if (memfs.existsSync(src)) { - memfs.copyFileSync(src, dest, mode); - } else { - const file = actualFs.readFileSync(src); - memfs.writeFileSync(dest, file); - } - }, - readdir: (path: PathLike, options: IReaddirOptions | string, callback: (err: NodeJS.ErrnoException | null, files: string[]) => void): any => { - options = options ?? { encoding: "utf-8" }; - return memfs.existsSync(path) ? memfs.readdir(path, options, callback as any) : actualFs.readdir(path, options as any, callback); - }, - readdirSync: ( - path: PathLike, - options?: - | { - encoding: BufferEncoding | null; - withFileTypes?: false | undefined; - } - | BufferEncoding - | null - ): TDataOut[] | Buffer[] | Dirent[] | string[] => { - options = options ?? { encoding: "utf-8" }; - return memfs.existsSync(path) ? memfs.readdirSync(path, options as any) : actualFs.readdirSync(path, options); - }, - writeFile: memfs.writeFile, - writeFileSync: (file: PathOrFileDescriptor, data: any, options?: any): void => { - const parent = dirname(file.toString()); - if (!memfs.existsSync(parent)) { - memfs.mkdirSync(parent, { recursive: true }); - } - memfs.writeFileSync(file, data, options ?? { encoding: "utf-8" }); - }, - writeSync: memfs.writeSync, - write: memfs.write, - mkdir: memfs.mkdir, - mkdirSync: ( - path: PathLike, - options: MakeDirectoryOptions & { - recursive: true; - } - ) => memfs.mkdirSync(path, options ?? { recursive: true }), - exists: (path: PathLike, callback: (exists: boolean) => void): void => - memfs.existsSync(path) ? memfs.exists(path, callback as any) : actualFs.exists(path, callback), - existsSync: (path: PathLike): boolean => memfs.existsSync(path) || actualFs.existsSync(path), - lstat: memfs.lstat, - lstatSync: (path: PathLike): Stats => (memfs.existsSync(path) ? memfs.lstatSync(path) : actualFs.lstatSync(path)), - fstat: memfs.fstat, - fstatSync: memfs.fstatSync, - stat: (path: PathLike, callback: TCallback): void => - memfs.existsSync(path) ? memfs.stat(path, callback as any) : actualFs.stat(path, callback), - statSync: (path: PathLike): Stats => (memfs.existsSync(path) ? memfs.statSync(path) : actualFs.statSync(path)), - createReadStream: (path: PathLike, options?: BufferEncoding | IReadStreamOptions): IReadStream | fs.ReadStream => - memfs.existsSync(path) ? memfs.createReadStream(path, options) : actualFs.createReadStream(path, options as any), - unlinkSync: memfs.unlinkSync, - realpathSync: (path: PathLike, options?: { encoding?: BufferEncoding | null } | BufferEncoding | null): string | TDataOut | Buffer => - memfs.existsSync(path) ? memfs.realpathSync(path, options as any) : actualFs.realpathSync(path, options), - openSync: (path: PathLike, flags: string | number, mode?: string | number): number => { - if (!memfs.existsSync(path) && actualFs.existsSync(path)) { - memfs.writeFileSync(path, actualFs.readFileSync(path)); - } else { - memfs.mkdirSync(dirname(path.toString()), { recursive: true }); - memfs.writeFileSync(path, ""); - } - return memfs.openSync(path, flags, mode); - }, - closeSync: memfs.closeSync, - watch: (path: PathLike, options?: IWatchOptions | string, listener?: (eventType: string, filename: string) => void) => - memfs.existsSync(path) ? memfs.watch(path, options, listener) : actualFs.watch(path, options as any, listener as any), - watchFile: ( - path: PathLike, - options: - | (WatchFileOptions & { - bigint: true; - }) - | undefined, - listener: (curr: Stats, prev: Stats) => void - ): StatWatcher => - memfs.existsSync(path) - ? (memfs.watchFile(path, options as any, listener as any) as any) - : actualFs.watchFile(path, options as any, listener), - unwatchFile: (path: PathLike, listener?: (curr: Stats, prev: Stats) => void): void => - memfs.existsSync(path) ? memfs.unwatchFile(path, listener as any) : actualFs.unwatchFile(path, listener), - } as any; -}; - -export const resetFs = (): void => { - vol.reset(); -}; diff --git a/packages/testing/test/__setup__/jest.setup.ts b/packages/testing/test/__setup__/jest.setup.ts deleted file mode 100644 index 0d029edd..00000000 --- a/packages/testing/test/__setup__/jest.setup.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createFs, resetFs } from "./fusion-fs"; - -jest.mock("fs", () => { - return createFs(jest.requireActual("memfs")); -}); - -jest.mock("fs/promises", () => { - return createFs(jest.requireActual("memfs")); -}); - -afterEach(() => { - jest.clearAllMocks(); - resetFs(); -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9e715236..17eb914d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -429,6 +429,13 @@ importers: version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) packages/test: + dependencies: + '@types/require-from-string': + specifier: ^1.2.3 + version: 1.2.3 + require-from-string: + specifier: ^2.0.2 + version: 2.0.2 devDependencies: '@eslint/js': specifier: ^9.1.1 @@ -529,6 +536,9 @@ importers: '@quatico/websmith-core': specifier: workspace:^ version: link:../core + require-from-string: + specifier: ^2.0.2 + version: 2.0.2 devDependencies: '@eslint/js': specifier: ^9.1.1 @@ -545,6 +555,9 @@ importers: '@types/jest': specifier: ^29.5.12 version: 29.5.12 + '@types/require-from-string': + specifier: ^1.2.3 + version: 1.2.3 concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -1928,6 +1941,9 @@ packages: '@types/react@18.2.79': resolution: {integrity: sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==} + '@types/require-from-string@1.2.3': + resolution: {integrity: sha512-kxLU5xvefySGpp1Z7VCt4m5AhQJUZ8HjW8ADdeS7GieqFPHLAde007fd9bxeXEsFXyaA0LeWIoQXyXP17mGpIg==} + '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -6088,6 +6104,8 @@ snapshots: '@types/prop-types': 15.7.12 csstype: 3.1.3 + '@types/require-from-string@1.2.3': {} + '@types/semver@7.5.8': {} '@types/stack-utils@2.0.3': {} From 3902a5e23e8b1414db62a8775e30e7f7e0c086c2 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Tue, 30 Apr 2024 00:58:44 +0200 Subject: [PATCH 05/52] r Removes extracted API from package test --- packages/test/src/setup/config.ts | 24 -------------------- packages/test/src/setup/copy.ts | 35 ------------------------------ packages/test/src/setup/execute.ts | 24 -------------------- packages/test/src/setup/expect.ts | 20 ----------------- packages/test/src/setup/index.ts | 6 ----- packages/test/src/setup/paths.ts | 10 --------- packages/test/src/setup/values.ts | 10 --------- 7 files changed, 129 deletions(-) delete mode 100644 packages/test/src/setup/config.ts delete mode 100644 packages/test/src/setup/copy.ts delete mode 100644 packages/test/src/setup/execute.ts delete mode 100644 packages/test/src/setup/expect.ts delete mode 100644 packages/test/src/setup/index.ts delete mode 100644 packages/test/src/setup/paths.ts delete mode 100644 packages/test/src/setup/values.ts diff --git a/packages/test/src/setup/config.ts b/packages/test/src/setup/config.ts deleted file mode 100644 index e07711c6..00000000 --- a/packages/test/src/setup/config.ts +++ /dev/null @@ -1,24 +0,0 @@ -import ts from "typescript"; -import { resolvePath } from "./paths"; -import { stringToArray } from "./values"; - -export const websmithConfig = (system: ts.System, configPath: string, content?: object) => { - const resolvedConfigPath = resolvePath(system, configPath); - system.writeFile(resolvedConfigPath, JSON.stringify({ addonsDir: "./addons", ...content })); -}; - -export const setConfig = (system: ts.System, configPath: string, cfgProp: string, cfgValue: string) => { - const resolvedConfigPath = resolvePath(system, configPath); - const content = JSON.parse(system.readFile(resolvedConfigPath, "utf-8") ?? "{}") as Record; - content[cfgProp] = stringToArray(cfgValue); - system.writeFile(resolvedConfigPath, JSON.stringify(content)); -}; - -export const setTargets = (system: ts.System, configPath: string, targetNames: string) => { - const resolvedConfigPath = resolvePath(system, configPath); - const content = JSON.parse(system.readFile(resolvedConfigPath, "utf-8") ?? "{}") as { targets?: Record }; - const targets: string[] = stringToArray(targetNames); - - content.targets = { ...(content.targets ?? {}), ...targets.map(it => ({ [it]: {} })) }; - system.writeFile(resolvedConfigPath, JSON.stringify(content)); -}; diff --git a/packages/test/src/setup/copy.ts b/packages/test/src/setup/copy.ts deleted file mode 100644 index 33e8732f..00000000 --- a/packages/test/src/setup/copy.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { basename, join } from "path"; -import ts from "typescript"; - -const copyFileSync = (system: ts.System, source: string, target: string) => { - let targetFile = target; - // If target is a directory, a new file with the same name will be created - if (system.directoryExists(target)) { - targetFile = join(target, basename(source)); - } - const fileContent = system.readFile(source); - if (fileContent) { - system.writeFile(targetFile, fileContent); - } -}; - -export const copyFolderSync = (system: ts.System, source: string, target: string) => { - let files = []; - // Check if folder needs to be created or integrated - const targetFolder = join(target, basename(source)); - if (!system.directoryExists(targetFolder)) { - system.createDirectory(targetFolder); - } - // Copy - if (system.directoryExists(source)) { - files = system.readDirectory(source); - files.forEach(file => { - const curSource = join(source, file); - if (system.directoryExists(curSource)) { - copyFolderSync(system, curSource, targetFolder); - } else { - copyFileSync(system, curSource, targetFolder); - } - }); - } -}; diff --git a/packages/test/src/setup/execute.ts b/packages/test/src/setup/execute.ts deleted file mode 100644 index c5f07416..00000000 --- a/packages/test/src/setup/execute.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createOptions } from "@quatico/websmith-compiler"; -import { Compiler } from "@quatico/websmith-core"; -import parseArgs from "minimist"; - -export const execute = (command: string) => { - let cmd: string = command; - if (cmd === "websmith") { - cmd = ""; - } else if (cmd.startsWith("websmith ")) { - cmd = cmd.replace("websmith ", ""); - } - - const args = cmd - .replace(", ", ",") - .split(" ") - .map(it => it.trim()) - .filter(it => it.length > 0); - - const compiler = new Compiler(createOptions({ ...parseArgs(args), buildDir: "./dist", project: "./tsconfig.json" })); - compiler.compile(); - const context = compiler.getContext()!; - - return { compiler, context }; -}; diff --git a/packages/test/src/setup/expect.ts b/packages/test/src/setup/expect.ts deleted file mode 100644 index 3b524a98..00000000 --- a/packages/test/src/setup/expect.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { AddonRegistry, Compiler } from "@quatico/websmith-core"; -import ts from "typescript"; -import { resolvePath } from "./paths"; - -export const activeAddons = (compilerOrRegistry: Compiler | AddonRegistry) => { - const target = isCompiler(compilerOrRegistry) ? compilerOrRegistry.getOptions().addons : compilerOrRegistry; - return target.getAvailableAddons().map(cur => cur.name); -}; - -export const fileContent = (system: ts.System, filePath: string, projectDir = process.cwd()): string | undefined => - system.readFile(resolvePath(system, projectDir, `${filePath}`), "utf-8"); - -export const pathExists = (system: ts.System, ...filePaths: string[]): boolean => - filePaths.reduce( - (acc, it) => acc && (system.fileExists(resolvePath(system, `${it}`)) || system.directoryExists(resolvePath(system, `${it}`))), - true - ); - -const isCompiler = (compilerOrRegistry: Compiler | AddonRegistry): compilerOrRegistry is Compiler => - compilerOrRegistry instanceof Compiler && !("getAddons" in compilerOrRegistry); diff --git a/packages/test/src/setup/index.ts b/packages/test/src/setup/index.ts deleted file mode 100644 index 90444cab..00000000 --- a/packages/test/src/setup/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from "./config"; -export * from "./copy"; -export * from "./execute"; -export * from "./expect"; -export * from "./paths"; -export * from "./values"; diff --git a/packages/test/src/setup/paths.ts b/packages/test/src/setup/paths.ts deleted file mode 100644 index 097bb210..00000000 --- a/packages/test/src/setup/paths.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { isAbsolute, join } from "path"; -import ts from "typescript"; - -export const resolvePath = (fs: ts.System, ...pathSegments: string[]) => { - let resolvedPath = join(...pathSegments); - if (!isAbsolute(resolvedPath)) { - resolvedPath = join(fs.getCurrentDirectory(), ...pathSegments); - } - return resolvedPath; -}; diff --git a/packages/test/src/setup/values.ts b/packages/test/src/setup/values.ts deleted file mode 100644 index 1a024ad7..00000000 --- a/packages/test/src/setup/values.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const stringToArray = (valueOrCommaSeparated: string): string[] => { - let result: string[] = [valueOrCommaSeparated]; - if (valueOrCommaSeparated.indexOf(",") > -1) { - result = valueOrCommaSeparated - .split(",") - .map(cur => cur.trim()) - .filter(cur => cur.length > 0); - } - return result; -}; From 9b300fe20cb9fdaa1b4769271f2b488cf17509ad Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Tue, 30 Apr 2024 00:59:12 +0200 Subject: [PATCH 06/52] e Removes dependency to websmith-api package from package test --- packages/test/jest.config.js | 1 - packages/test/package.json | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/test/jest.config.js b/packages/test/jest.config.js index 8e1be420..f87f72c8 100644 --- a/packages/test/jest.config.js +++ b/packages/test/jest.config.js @@ -8,7 +8,6 @@ module.exports = { moduleFileExtensions: ["ts", "js", "json", "node"], moduleNameMapper: { - "@quatico/websmith-api": "/../api/src", "@quatico/websmith-core": "/../core/src", "@quatico/websmith-compiler": "/../compiler/src", }, diff --git a/packages/test/package.json b/packages/test/package.json index c7aa549e..13b2bd04 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -16,10 +16,8 @@ "devDependencies": { "@eslint/js": "^9.1.1", "@nx/eslint-plugin": "^18.3.3", - "@quatico/websmith-api": "workspace:^", "@quatico/websmith-compiler": "workspace:^", "@quatico/websmith-core": "workspace:^", - "@quatico/websmith-testing": "workspace:^", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", From a3bfeb120e1a32291c6c9c4c2ab5d4f0c704d401 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Tue, 30 Apr 2024 01:00:01 +0200 Subject: [PATCH 07/52] F Adds handling of project files to testing API for websmith addons --- .../src/compilation/environment.spec.ts | 142 +++++++++++++++--- .../testing/src/compilation/environment.ts | 70 +++++++-- 2 files changed, 173 insertions(+), 39 deletions(-) diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index b912895b..a245da54 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -141,72 +141,86 @@ describe("compilationEnv#addons", () => { }); describe("compilationEnv#projects", () => { - it("should yield no projects with defaults", () => { + afterEach(() => { + testObj.cleanUp(); + }); + + it("should yield empty project with defaults", () => { testObj = compilationEnv("/target").addProject("expected-project"); const actual = testObj.getProjects(); - expect(actual).toHaveLength(0); + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toHaveLength(0); }); it("should yield project with project files and file names", () => { testObj = compilationEnv("/target"); - testObj.addProject("expected-project", { projectFiles: { "index.ts": `export * from "./target";`, "target.ts": `export class Target {}` } }); + testObj.addProject("expected-project", { "index.ts": `export * from "./target";`, "target.ts": `export class Target {}` }); const actual = testObj.getProjects(); - expect(actual).toEqual(["/target/expected-project"]); + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); }); it("should yield project with project files and relative paths", () => { testObj = compilationEnv("/target"); testObj.addProject("expected-project", { - projectFiles: { "./foo-bar/index.ts": `export * from "./target";`, "./foo-bar/target.ts": `export class Target {}` }, + "./foo-bar/index.ts": `export * from "./target";`, + "./foo-bar/target.ts": `export class Target {}`, }); const actual = testObj.getProjects(); - expect(actual).toEqual(["/target/expected-project"]); + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/foo-bar/index.ts", "/target/expected-project/foo-bar/target.ts"]); }); it("should yield project with project files and relative project paths", () => { testObj = compilationEnv("/target"); testObj.addProject("expected-project", { - projectFiles: { "./expected-project/index.ts": `export * from "./target";`, "./expected-project/target.ts": `export class Target {}` }, + "./expected-project/index.ts": `export * from "./target";`, + "./expected-project/target.ts": `export class Target {}`, }); const actual = testObj.getProjects(); - expect(actual).toEqual(["/target/expected-project"]); + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); }); it("should yield project with project files and absolute paths", () => { testObj = compilationEnv("/target"); testObj.addProject("expected-project", { - projectFiles: { - "/target/expected-project/index.ts": `export * from "./target";`, - "/target/expected-project/target.ts": `export class Target {}`, - }, + "/target/expected-project/index.ts": `export * from "./target";`, + "/target/expected-project/target.ts": `export class Target {}`, }); const actual = testObj.getProjects(); - expect(actual).toEqual(["/target/expected-project"]); + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); }); - it("should yield no projects with project files and invalid absolute paths", () => { + it("should yield empty project with invalid absolute paths", () => { testObj = compilationEnv("/target"); testObj.addProject("expected-project", { - projectFiles: { - // buildDir is missing in absolute paths - "/expected-project/index.ts": `export * from "./target";`, - "/expected-project/target.ts": `export class Target {}`, - }, + // buildDir is missing in absolute paths + "/expected-project/index.ts": `export * from "./target";`, + "/expected-project/target.ts": `export class Target {}`, }); const actual = testObj.getProjects(); - expect(actual).toHaveLength(0); + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toHaveLength(0); }); it("should yield project with single project in default projects path", () => { @@ -218,7 +232,9 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjects(); - expect(actual).toEqual(["/target/expected-project"]); + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); }); it("should yield projects with multiple projects in default projects path", () => { @@ -232,7 +248,11 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjects(); - expect(actual).toEqual(["/target/expected-project1", "/target/expected-project2"]); + expect(actual).toHaveLength(2); + expect(actual[0].getPath()).toBe("/target/expected-project1"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project1/index.ts", "/target/expected-project1/one.ts"]); + expect(actual[1].getPath()).toBe("/target/expected-project2"); + expect(actual[1].getFiles()).toEqual(["/target/expected-project2/index.ts", "/target/expected-project2/two.ts"]); }); it("should yield project with single project in custom projects path", () => { @@ -240,10 +260,84 @@ describe("compilationEnv#projects", () => { testObj.getSystem().writeFile("/custom-projects/expected-project/index.ts", `export * from "./target";`); testObj.getSystem().writeFile("/custom-projects/expected-project/target.ts", `export class Target {}`); - testObj.addProject("expected-project", { sourceDir: "../custom-projects/" }); + testObj.addProject("expected-project", "../custom-projects/"); + + const actual = testObj.getProjects(); + + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + }); + + it("should yield project and add file with file name", () => { + testObj = compilationEnv("/target").addProject("expected-project"); + + testObj.getProject("expected-project")!.addFile("index.ts", `export * from "./target";`).addFile("target.ts", `export class Target {}`); + + const actual = testObj.getProjects(); + + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + }); + + it("should yield project and add files with relative paths", () => { + testObj = compilationEnv("/target").addProject("expected-project"); + + testObj + .getProject("expected-project")! + .addFile("./foo-bar/index.ts", `export * from "./target";`) + .addFile("./foo-bar/target.ts", `export class Target {}`); + + const actual = testObj.getProjects(); + + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/foo-bar/index.ts", "/target/expected-project/foo-bar/target.ts"]); + }); + + it("should yield project and add files with relative project paths", () => { + testObj = compilationEnv("/target").addProject("expected-project"); + + testObj + .getProject("expected-project")! + .addFile("./expected-project/index.ts", `export * from "./target";`) + .addFile("./expected-project/target.ts", `export class Target {}`); + + const actual = testObj.getProjects(); + + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + }); + + it("should yield project and add files with absolute paths", () => { + testObj = compilationEnv("/target").addProject("expected-project"); + + testObj + .getProject("expected-project")! + .addFile("/target/expected-project/index.ts", `export * from "./target";`) + .addFile("/target/expected-project/target.ts", `export class Target {}`); + + const actual = testObj.getProjects(); + + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + }); + + it("should yield empty project with invalid absolute paths added", () => { + testObj = compilationEnv("/target").addProject("expected-project"); + + testObj + .getProject("expected-project")! + .addFile("/expected-project/index.ts", `export * from "./target";`) + .addFile("/expected-project/target.ts", `export class Target {}`); const actual = testObj.getProjects(); - expect(actual).toEqual(["/target/expected-project"]); + expect(actual).toHaveLength(1); + expect(actual[0].getPath()).toBe("/target/expected-project"); + expect(actual[0].getFiles()).toHaveLength(0); }); }); diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 80bc7ba9..4f93da95 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -79,20 +79,31 @@ export class CompilationEnv { return this; } - public getProjects(): string[] { + public getProject(projectName: string): Project | undefined { const buildDir = this.getCompilerOptions().buildDir; - const projectDirs = this.system.readDirectory(buildDir).map(it => { - const end = it.indexOf("/", buildDir.length + 1); - return it.substring(0, end); - }); - return [...new Set(projectDirs)]; + const projectDir = this.system.getDirectories(buildDir).find(it => it === projectName); + if (projectDir) { + return new Project(resolvePath(this.system, buildDir, projectDir), this.system); + } + return undefined; + } + + public getProjects(): Project[] { + const buildDir = this.getCompilerOptions().buildDir; + const projectDirs = this.system.getDirectories(buildDir); + return projectDirs.map(it => resolvePath(this.system, buildDir, it)).map(it => new Project(it, this.system)); } - public addProject(projectName: string, options?: { sourceDir?: string; projectFiles?: Record }): this { - const { sourceDir = "../test-data/projects/", projectFiles } = options ?? {}; - if (projectFiles) { + public addProject(projectName: string, source?: string | Record): this { + const isFiles = (source?: string | Record): source is Record => typeof source === "object"; + const projectPath = resolvePath(this.system, this.rootDir, projectName); + + if (!this.system.directoryExists(projectPath)) { + this.system.createDirectory(projectPath); + } + if (isFiles(source)) { this.addFiles( - Object.entries(projectFiles).reduce((acc: Record, [filePath, content]) => { + Object.entries(source).reduce((acc: Record, [filePath, content]) => { if (isAbsolute(filePath)) { acc[filePath] = content; } else { @@ -106,17 +117,13 @@ export class CompilationEnv { }, {}) ); } else { + const sourceDir = source ?? "../test-data/projects/"; const projectDir = resolvePath(this.system, this.rootDir, sourceDir, projectName); copyFolderSync(this.system, projectDir, this.getCompilerOptions().buildDir); } return this; } - public addSourceFile(fileName: string, content: string): this { - this.system.writeFile(resolvePath(this.system, "src", fileName), content); - return this; - } - private addAddonFile(addonName: string, addonCode: string) { this.system.writeFile(resolvePath(this.system, this.getAddons().getAddonDir(), addonName, "addon.ts"), addonCode); } @@ -172,6 +179,39 @@ export type CompilationOptions = { virtual?: boolean; }; +export class Project { + private path: string; + private system: ts.System; + + constructor(path: string, system: ts.System) { + this.path = path; + this.system = system; + } + + public getPath(): string { + return this.path; + } + + public addFile(filePath: string, content: string): this { + let path; + if (isAbsolute(filePath)) { + path = resolvePath(this.system, filePath); + } else { + if (filePath.includes(basename(this.path))) { + path = resolvePath(this.system, dirname(this.path), filePath); + } else { + path = resolvePath(this.system, this.path, filePath); + } + } + this.system.writeFile(path, content); + return this; + } + + public getFiles(): string[] { + return this.system.readDirectory(this.path); + } +} + export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => { // if (withDefaults && !existsSync(join(projectDir, "websmith.config.json"))) { // writeFileSync( From 8f3fc0025906d5f4f62d496813886c21d217ba85 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Tue, 30 Apr 2024 01:34:33 +0200 Subject: [PATCH 08/52] F Adds initial documentation of the testing API --- packages/testing/README.md | 80 +++++++++++++++++++ .../src/compilation/environment.spec.ts | 62 ++++++-------- .../testing/src/compilation/environment.ts | 14 +--- packages/testing/src/compilation/index.ts | 1 + packages/testing/src/index.ts | 1 + 5 files changed, 107 insertions(+), 51 deletions(-) create mode 100644 packages/testing/README.md create mode 100644 packages/testing/src/compilation/index.ts diff --git a/packages/testing/README.md b/packages/testing/README.md new file mode 100644 index 00000000..dfb4bfb1 --- /dev/null +++ b/packages/testing/README.md @@ -0,0 +1,80 @@ +# Websmith Testing API + +This library provides a simple API for testing Websmith addons in your project. + +## Installation + +```bash +npm add -D @quatico/websmith-testing +``` + +## Usage: Test addon with an existing test project + +Compile a project with from an existing folder in `test-data/projects` with +a addon from the `addons` folder in your filesystem. + +```typescript +// foobar-addon.test.ts +import { compilationEnv } from '@quatico/websmith-testing'; + +describe('FoobarAddon', () => { + it('should compile', () => { + const results = compilationEnv('/target') + .addAddons(['foobar-addon'], "../addons") + .addProject("simple-example", "../test-data/projects") + .compile(); + + expect(fileContent("simple.js")).toMatchInlineSnapshot(` + "import { foo } from 'foobar-addon'; + foo(); + " + `); + }); +}); +``` + +Please note that the whole compilation is done in memory and no files are written to disk. If you want to write the compiled files to disk, you can use the options `virtual: false`: + +```typescript +// foobar-addon.test.ts +import { compilationEnv, type CompilationEnv } from '@quatico/websmith-testing'; + +let compilation: CompilationEnv; + +afterEach(() => { + // Remove the compilation results from your disk + compilation.cleanup(); +}); + +describe('FoobarAddon', () => { + it('should compile', () => { + const compilation = compilationEnv('/target', { virtual: false }); + + // Use the example from above + // Add addon and project to the compilation environment + }); +}); + +``` + +## Usage: Test addon with virtual file content from your test + +You can define the project files to be used to test your addon directly within your test: + +```typescript +// foobar-addon.test.ts +import { compilationEnv } from '@quatico/websmith-testing'; + +describe('FoobarAddon', () => { + it('should compile', () => { + const results = compilationEnv('/target').addProject("expected-project", { + "./foo-bar/index.ts": `export * from "./target";`, + "./foo-bar/target.ts": `export class Target {}`, + }) + .addAddons(['foobar-addon'], "../addons") + .compile(); + + // expect the compilation results + }); +}); +``` diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index a245da54..3f117aba 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -3,17 +3,11 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import ts from "typescript"; -import { compilationEnv, type CompilationEnv } from "./environment"; - -let testObj: CompilationEnv; +import { compilationEnv } from "./environment"; describe("compilationEnv", () => { - afterEach(() => { - testObj.cleanUp(); - }); - it("should yield default configuration with defaults", () => { - testObj = compilationEnv("expected"); + const testObj = compilationEnv("expected"); expect(testObj.getRootDir().endsWith("/expected")).toBe(true); expect(testObj.getCompiler()).toBeDefined(); @@ -23,7 +17,7 @@ describe("compilationEnv", () => { }); it("should yield default compiler options with defaults", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); const actual = testObj.getCompilerOptions(); @@ -46,7 +40,7 @@ describe("compilationEnv", () => { }); it("should yield custom compiler options with custom overrides", () => { - testObj = compilationEnv("/target", { compilerOptions: { buildDir: "/expected-src", project: { outDir: "/expected-out" } } }); + const testObj = compilationEnv("/target", { compilerOptions: { buildDir: "/expected-src", project: { outDir: "/expected-out" } } }); const actual = testObj.getCompilerOptions(); @@ -63,12 +57,8 @@ describe("compilationEnv", () => { }); describe("compilationEnv#addons", () => { - afterEach(() => { - testObj.cleanUp(); - }); - it("should yields no addons with defaults", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); const actual = testObj.getAddons(); @@ -77,7 +67,7 @@ describe("compilationEnv#addons", () => { }); it("should yield addon with valid addon source", () => { - testObj = compilationEnv("/target").addAddon("expected-addon", `export const activate = () => {};`); + const testObj = compilationEnv("/target").addAddon("expected-addon", `export const activate = () => {};`); const actual = testObj .getAddons() @@ -88,7 +78,7 @@ describe("compilationEnv#addons", () => { }); it("should yield no addons with invalid addon source", () => { - testObj = compilationEnv("/target").addAddon("invalid-addon", `export const NO_ACTIVATE_FUNCTION = true;`); + const testObj = compilationEnv("/target").addAddon("invalid-addon", `export const NO_ACTIVATE_FUNCTION = true;`); const actual = testObj.getAddons().getAvailableAddons(); @@ -96,7 +86,7 @@ describe("compilationEnv#addons", () => { }); it("should yield addon with single addon in default addons path", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.getSystem().writeFile("/test-data/addons/expected-addon/addon.ts", `export const activate = () => {};`); testObj.addAddons(["expected-addon"]); @@ -110,7 +100,7 @@ describe("compilationEnv#addons", () => { }); it("should yield addons with multiple addons in default addons path", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.getSystem().writeFile("/test-data/addons/expected-addon1/addon.ts", `export const activate = () => {};`); testObj.getSystem().writeFile("/test-data/addons/expected-addon2/addon.ts", `export const activate = () => {};`); @@ -125,7 +115,7 @@ describe("compilationEnv#addons", () => { }); it("should yield addons with multiple addons in custom addons path", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.getSystem().writeFile("/target/custom-addons-folder/expected-addon1/addon.ts", `export const activate = () => {};`); testObj.getSystem().writeFile("/target/custom-addons-folder/expected-addon2/addon.ts", `export const activate = () => {};`); @@ -141,12 +131,8 @@ describe("compilationEnv#addons", () => { }); describe("compilationEnv#projects", () => { - afterEach(() => { - testObj.cleanUp(); - }); - it("should yield empty project with defaults", () => { - testObj = compilationEnv("/target").addProject("expected-project"); + const testObj = compilationEnv("/target").addProject("expected-project"); const actual = testObj.getProjects(); @@ -156,7 +142,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with project files and file names", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.addProject("expected-project", { "index.ts": `export * from "./target";`, "target.ts": `export class Target {}` }); const actual = testObj.getProjects(); @@ -167,7 +153,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with project files and relative paths", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.addProject("expected-project", { "./foo-bar/index.ts": `export * from "./target";`, "./foo-bar/target.ts": `export class Target {}`, @@ -181,7 +167,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with project files and relative project paths", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.addProject("expected-project", { "./expected-project/index.ts": `export * from "./target";`, "./expected-project/target.ts": `export class Target {}`, @@ -195,7 +181,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with project files and absolute paths", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.addProject("expected-project", { "/target/expected-project/index.ts": `export * from "./target";`, "/target/expected-project/target.ts": `export class Target {}`, @@ -209,7 +195,7 @@ describe("compilationEnv#projects", () => { }); it("should yield empty project with invalid absolute paths", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.addProject("expected-project", { // buildDir is missing in absolute paths "/expected-project/index.ts": `export * from "./target";`, @@ -224,7 +210,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with single project in default projects path", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.getSystem().writeFile("/test-data/projects/expected-project/index.ts", `export * from "./target";`); testObj.getSystem().writeFile("/test-data/projects/expected-project/target.ts", `export class Target {}`); @@ -238,7 +224,7 @@ describe("compilationEnv#projects", () => { }); it("should yield projects with multiple projects in default projects path", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.getSystem().writeFile("/test-data/projects/expected-project1/index.ts", `export * from "./one";`); testObj.getSystem().writeFile("/test-data/projects/expected-project1/one.ts", `export class One {}`); testObj.getSystem().writeFile("/test-data/projects/expected-project2/index.ts", `export * from "./two";`); @@ -256,7 +242,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with single project in custom projects path", () => { - testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target"); testObj.getSystem().writeFile("/custom-projects/expected-project/index.ts", `export * from "./target";`); testObj.getSystem().writeFile("/custom-projects/expected-project/target.ts", `export class Target {}`); @@ -270,7 +256,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project and add file with file name", () => { - testObj = compilationEnv("/target").addProject("expected-project"); + const testObj = compilationEnv("/target").addProject("expected-project"); testObj.getProject("expected-project")!.addFile("index.ts", `export * from "./target";`).addFile("target.ts", `export class Target {}`); @@ -282,7 +268,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project and add files with relative paths", () => { - testObj = compilationEnv("/target").addProject("expected-project"); + const testObj = compilationEnv("/target").addProject("expected-project"); testObj .getProject("expected-project")! @@ -297,7 +283,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project and add files with relative project paths", () => { - testObj = compilationEnv("/target").addProject("expected-project"); + const testObj = compilationEnv("/target").addProject("expected-project"); testObj .getProject("expected-project")! @@ -312,7 +298,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project and add files with absolute paths", () => { - testObj = compilationEnv("/target").addProject("expected-project"); + const testObj = compilationEnv("/target").addProject("expected-project"); testObj .getProject("expected-project")! @@ -327,7 +313,7 @@ describe("compilationEnv#projects", () => { }); it("should yield empty project with invalid absolute paths added", () => { - testObj = compilationEnv("/target").addProject("expected-project"); + const testObj = compilationEnv("/target").addProject("expected-project"); testObj .getProject("expected-project")! diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 4f93da95..b697e932 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -178,7 +178,6 @@ export type CompilationOptions = { useCaseSensitiveFileNames?: boolean; virtual?: boolean; }; - export class Project { private path: string; private system: ts.System; @@ -212,15 +211,4 @@ export class Project { } } -export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => { - // if (withDefaults && !existsSync(join(projectDir, "websmith.config.json"))) { - // writeFileSync( - // join(projectDir, "websmith.config.json"), - // JSON.stringify({ - // addonsDir: "./addons", - // }) - // ); - // } - - return new CompilationEnv(rootDir, options); -}; +export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => new CompilationEnv(rootDir, options); diff --git a/packages/testing/src/compilation/index.ts b/packages/testing/src/compilation/index.ts new file mode 100644 index 00000000..b9e1dabb --- /dev/null +++ b/packages/testing/src/compilation/index.ts @@ -0,0 +1 @@ +export { compilationEnv, type CompilationOptions, type CompilationEnv } from "./environment"; diff --git a/packages/testing/src/index.ts b/packages/testing/src/index.ts index bbb6a9af..dc244e53 100644 --- a/packages/testing/src/index.ts +++ b/packages/testing/src/index.ts @@ -9,3 +9,4 @@ export * from "./compile-options"; export * from "./compile-system"; export * from "./fusion-fs"; export * from "./tsLibMocks"; +export * from "./compilation"; From 8e083735e6f549b61341032803afe1c074217165 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Wed, 1 May 2024 21:38:43 +0200 Subject: [PATCH 09/52] F Provides working API for handling of project and addon files --- packages/compiler/src/command.spec.ts | 49 +-- packages/compiler/src/options.spec.ts | 42 +-- .../src/compiler/addons/AddonRegistry.spec.ts | 14 +- .../core/src/compiler/addons/AddonRegistry.ts | 2 +- .../compiler/addons/addon-resolver.spec.ts | 2 +- packages/test/package.json | 1 + .../test/src/test-examples/bar-addon.test.ts | 119 +++----- .../testing/src/compilation/copy-directory.ts | 32 ++ packages/testing/src/compilation/copy.ts | 34 --- .../src/compilation/environment.spec.ts | 280 ++++++++---------- .../testing/src/compilation/environment.ts | 212 ++++++++----- packages/testing/src/compile-options.ts | 8 +- packages/webpack/src/options.spec.ts | 40 +-- pnpm-lock.yaml | 10 - 14 files changed, 386 insertions(+), 459 deletions(-) create mode 100644 packages/testing/src/compilation/copy-directory.ts delete mode 100644 packages/testing/src/compilation/copy.ts diff --git a/packages/compiler/src/command.spec.ts b/packages/compiler/src/command.spec.ts index a521aa04..01895d3d 100644 --- a/packages/compiler/src/command.spec.ts +++ b/packages/compiler/src/command.spec.ts @@ -210,7 +210,7 @@ describe("addCompileCommand#addons", () => { }, { virtual: true } ); - testSystem.writeFile("./addons/expected/addon.ts", "export const activate = () => {};"); + testSystem.writeFile("./addons/expected/addon.js", "export const activate = () => {};"); const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--addons", "expected"], { from: "user" }); @@ -218,15 +218,15 @@ describe("addCompileCommand#addons", () => { expect( target .getOptions() - .addons.getAddons() + .addons.getAvailableAddons() .map((it: CompilerAddon) => it.name) ).toEqual(["expected"]); }); it("should yield options addons w/ --addons cli argument and multiple existing addons", () => { - testSystem.writeFile("./addons/zip/addon.ts", "export const activate = () => {};"); - testSystem.writeFile("./addons/zap/addon.ts", "export const activate = () => {};"); - testSystem.writeFile("./addons/zup/addon.ts", "export const activate = () => {};"); + testSystem.writeFile("./addons/zip/addon.js", "export const activate = () => {};"); + testSystem.writeFile("./addons/zap/addon.js", "export const activate = () => {};"); + testSystem.writeFile("./addons/zup/addon.js", "export const activate = () => {};"); jest.mock( "/addons/zip/addon", () => { @@ -257,7 +257,7 @@ describe("addCompileCommand#addons", () => { expect( target .getOptions() - .addons.getAddons() + .addons.getAvailableAddons() .map((it: CompilerAddon) => it.name) ).toEqual(["zip", "zap", "zup"]); }); @@ -267,11 +267,11 @@ describe("addCompileCommand#addons", () => { addCompileCommand(new Command(), target).parse(["--addons", "unknown"], { from: "user" }); - expect(target.getOptions().addons.getAddons()).toEqual([]); + expect(target.getOptions().addons.getAvailableAddons()).toEqual([]); }); it("should not yield non-existing options addons w/ --addons cli argument, existing and non-existing addons", () => { - testSystem.writeFile("./addons/expected/addon.ts", "export const activate = () => {};"); + testSystem.writeFile("./addons/expected/addon.js", "export const activate = () => {};"); jest.mock( "/addons/expected/addon", () => { @@ -287,7 +287,7 @@ describe("addCompileCommand#addons", () => { expect( target .getOptions() - .addons.getAddons() + .addons.getAvailableAddons() .map((it: CompilerAddon) => it.name) ).toEqual(["expected"]); }); @@ -302,7 +302,7 @@ describe("addCompileCommand#addons", () => { }); it("should yield warning w/ --addons cli argument, existing and non-existing addons", () => { - testSystem.writeFile("./addons/existing/addon.ts", "export const activate = () => {};"); + testSystem.writeFile("./addons/existing/addon.js", "export const activate = () => {};"); jest.mock( "/addons/existing/addon", () => { @@ -320,7 +320,7 @@ describe("addCompileCommand#addons", () => { }); it("should yield addonsDir and addons from compiler config w/o any cli argument", () => { - testSystem.writeFile("/expected/one/addon.ts", "export const activate = () => {};"); + testSystem.writeFile("/expected/one/addon.js", "export const activate = () => {};"); jest.mock( "/expected/one/addon", () => { @@ -333,29 +333,10 @@ describe("addCompileCommand#addons", () => { addCompileCommand(new Command(), target).parse([], { from: "user" }); - expect(target.getOptions().addons).toMatchInlineSnapshot(` - AddonRegistry { - "addons": [ - "one", - "two", - ], - "availableAddons": Map { - "one" => { - "activate": [Function], - "name": "one", - }, - }, - "config": { - "addons": [ - "one", - "two", - ], - "addonsDir": "/expected", - "configFilePath": "/websmith.config.json", - }, - "reporter": NoReporter {}, - } - `); + expect(target.getOptions().addons).toMatchObject({ + addons: ["one", "two"], + availableAddons: {}, + }); }); }); diff --git a/packages/compiler/src/options.spec.ts b/packages/compiler/src/options.spec.ts index 7dabd21c..b8134e6a 100644 --- a/packages/compiler/src/options.spec.ts +++ b/packages/compiler/src/options.spec.ts @@ -39,7 +39,7 @@ describe("createOptions", () => { it("should return expected path w/ custom addons directory", () => { const { fileSystem: target } = compileSystem({ - "./expected/addon-foo/addon.ts": "export const activate = () => {};", + "./expected/addon-foo/addon.js": "export const activate = () => {};", }); jest.mock( "/expected/addon-foo/addon", @@ -49,7 +49,7 @@ describe("createOptions", () => { { virtual: true } ); - const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.getAddons(); + const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.getAvailableAddons(); expect(actual.map(it => it.name)).toEqual(["addon-foo"]); }); @@ -84,8 +84,8 @@ describe("createOptions", () => { it("should return config w/ valid addonsDir, addons in compiler config json", () => { const { fileSystem: target } = compileSystem({ - "/expected/one/addon.ts": "export const activate = () => {};", - "websmith.config.json": '{ "addons":["one", "two"], "addonsDir":"./expected" }', + "./expected/one/addon.js": "export const activate = () => {};", + "./websmith.config.json": '{ "addons":["one", "two"], "addonsDir":"./expected" }', }); jest.mock( "/expected/one/addon", @@ -97,28 +97,16 @@ describe("createOptions", () => { const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).addons; - expect(actual).toMatchInlineSnapshot(` - AddonRegistry { - "addons": [ - "one", - "two", - ], - "availableAddons": Map { - "one" => { - "activate": [MockFunction], - "name": "one", - }, - }, - "config": { - "addons": [ - "one", - "two", - ], - "addonsDir": "/expected", - "configFilePath": "/websmith.config.json", - }, - "reporter": NoReporter {}, - } - `); + expect(actual).toMatchObject({ + addons: ["one", "two"], + availableAddons: new Map( + Object.entries({ + one: { + activate: expect.any(Function), + name: "one", + }, + }) + ), + }); }); }); diff --git a/packages/core/src/compiler/addons/AddonRegistry.spec.ts b/packages/core/src/compiler/addons/AddonRegistry.spec.ts index 3960c2c2..55c86ca4 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.spec.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.spec.ts @@ -58,7 +58,7 @@ describe("getAddons", () => { }); it("returns addons w/ single addon in addon directory", () => { - system.writeFile("./addons/expected/addon.ts", "export const activate = () => {};"); + system.writeFile("./addons/expected/addon.js", "export const activate = () => {};"); jest.mock( "/addons/expected/addon", () => { @@ -73,7 +73,7 @@ describe("getAddons", () => { }); it("returns addons w/ multiple addons in addon directory", () => { - system.writeFile("./addons/one/addon.ts", "export const activate = () => {};"); + system.writeFile("./addons/one/addon.js", "export const activate = () => {};"); jest.mock( "/addons/one/addon", () => { @@ -81,7 +81,7 @@ describe("getAddons", () => { }, { virtual: true } ); - system.writeFile("./addons/two/addon.ts", "export const activate = () => {};"); + system.writeFile("./addons/two/addon.js", "export const activate = () => {};"); jest.mock( "/addons/two/addon", () => { @@ -89,7 +89,7 @@ describe("getAddons", () => { }, { virtual: true } ); - system.writeFile("./addons/three/addon.ts", "export const activate = () => {};"); + system.writeFile("./addons/three/addon.js", "export const activate = () => {};"); jest.mock( "/addons/three/addon", () => { @@ -104,7 +104,7 @@ describe("getAddons", () => { }); it("returns valid addons w/ invalid and valid addons in addon directory", () => { - system.writeFile("./addons/expected/addon.ts", "export const activate = () => {};"); + system.writeFile("./addons/expected/addon.js", "export const activate = () => {};"); jest.mock( "/addons/expected/addon", () => { @@ -112,7 +112,7 @@ describe("getAddons", () => { }, { virtual: true } ); - system.writeFile("./addons/invalid/addon.ts", "export const whatever = () => {};"); + system.writeFile("./addons/invalid/addon.js", "export const whatever = () => {};"); jest.mock( "/addons/invalid/addon", () => { @@ -127,7 +127,7 @@ describe("getAddons", () => { }); it("returns no addons w/ empty files in addon directory", () => { - system.writeFile("./addons/empty/addon.ts", ""); + system.writeFile("./addons/empty/addon.js", ""); jest.mock( "/addons/empty/addon", () => { diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index 36a79f2d..5e855f1c 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -42,7 +42,7 @@ export class AddonRegistry { return Array.from(this.availableAddons.values()); } - public getAddonDir(): string { + public getAddonsDir(): string { return this.options.addonsDir; } diff --git a/packages/core/src/compiler/addons/addon-resolver.spec.ts b/packages/core/src/compiler/addons/addon-resolver.spec.ts index e6894ff9..8bbcb4d6 100644 --- a/packages/core/src/compiler/addons/addon-resolver.spec.ts +++ b/packages/core/src/compiler/addons/addon-resolver.spec.ts @@ -29,7 +29,7 @@ beforeAll(() => { }); describe("createResolver", () => { - it("reads addon.ts files from existing addon folder", () => { + it("reads addon.js files from existing addon folder", () => { const resolve = createResolver(new NoReporter(), testSystem); const actual = resolve(["one"]); diff --git a/packages/test/package.json b/packages/test/package.json index 13b2bd04..9550c9d7 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -18,6 +18,7 @@ "@nx/eslint-plugin": "^18.3.3", "@quatico/websmith-compiler": "workspace:^", "@quatico/websmith-core": "workspace:^", + "@quatico/websmith-testing": "workspace:^", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", diff --git a/packages/test/src/test-examples/bar-addon.test.ts b/packages/test/src/test-examples/bar-addon.test.ts index 219a8a70..27fbaa46 100644 --- a/packages/test/src/test-examples/bar-addon.test.ts +++ b/packages/test/src/test-examples/bar-addon.test.ts @@ -1,100 +1,53 @@ -import { activeAddons, execute, fileContent, pathExists, setUp } from "../setup"; - -const { rootDir, cleanUp, compiler, addAddons, addProject, system } = setUp("__TEMP__"); - -beforeAll(() => { - addAddons("foo-addon", "../test-data/addons/"); -}); - -afterAll(() => { - cleanUp(rootDir); -}); +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import { compilationEnv } from "@quatico/websmith-testing"; describe("test-project-foo", () => { - let projectDir: string; - beforeEach(() => { - projectDir = addProject("test-project-foo", rootDir, "../test-data/projects/"); - }); + it("should install addon successfully", () => { + const testObj = compilationEnv("__TEST__").addAddon("foo-addon", "../test-data/addons"); - afterEach(() => { - cleanUp(projectDir); - }); + const actual = testObj.getActiveAddons().map(it => it.name); - it("should install addon successfully", () => { - expect(activeAddons(compiler)).toContain("foo-addon"); + expect(actual).toContain("foo-addon"); }); it("should contain source file", () => { - const actual = fileContent(system, projectDir, "src/foo.ts"); - - expect(actual).toMatchInlineSnapshot(` - "export const foo = (): void => { - console.log("foo"); - }; - " - `); + const testObj = compilationEnv("__TEST__").addProjectFile( + "src/foo.ts", + ` + export const foo = () => { + console.log("foo"); + }; + ` + ); + + const actual = testObj.getProjectFile("foo.ts"); + + expect(actual).toMatchInlineSnapshot( + ` + export const foo = () => { + console.log("foo"); + }; + ` + ); }); it("should compile source file content", () => { - execute("websmith compiler"); - - expect(fileContent(system, "dist/foo.js")).toMatchInlineSnapshot(` - "export const foo = () => { + const testObj = compilationEnv("__TEST__").addProjectFile( + "src/foo.ts", + ` + export const foo = () => { console.log("foo"); }; - " - `); - }); -}); + ` + ); -describe("test-project-foobar", () => { - beforeEach(() => { - addProject("test-project-foobar"); - }); + const actual = testObj.compile(); - afterEach(() => { - cleanUp(); - }); - - it("should contain source files", () => { - expect(pathExists(system, "src/foobar.ts", "src/whatever.ts")).toBe(true); - }); - - it("should compile foobar.ts content", () => { - execute("websmith compiler"); - - expect(fileContent(system, "dist/foobar.js")).toMatchInlineSnapshot(` - ""use strict"; - /* eslint-disable @typescript-eslint/no-unused-vars */ - function foobar() { - console.log("foobar"); - return "foobar"; - } - " - `); - }); -}); - -describe("test-project-one", () => { - let projectDir: string; - beforeEach(() => { - projectDir = addProject("test-project-one", rootDir, "../test-data/projects/"); - }); - - afterEach(() => { - cleanUp(projectDir); - }); - - it("should contain source file", () => { - expect(pathExists(system, "src/one.ts", "src/two.ts", "src/three.ts")).toBe(true); - }); - - it("should compile one.ts content", () => { - execute("websmith compiler"); - - expect(fileContent(system, "dist/one.js")).toMatchInlineSnapshot(` - "export const one = () => { - console.log("one"); + expect(actual.emittedFiles![0]).toMatchInlineSnapshot(` + "export const foo = () => { + console.log("foo"); }; " `); diff --git a/packages/testing/src/compilation/copy-directory.ts b/packages/testing/src/compilation/copy-directory.ts new file mode 100644 index 00000000..03fdb2a1 --- /dev/null +++ b/packages/testing/src/compilation/copy-directory.ts @@ -0,0 +1,32 @@ +import { join } from "path"; +import ts from "typescript"; + +export const copyDirectory = (system: ts.System, source: string, target: string, kind: "project" | "addon") => { + // Throw an error if the source directory does not exist for addons + if (kind === "addon" && !system.directoryExists(source)) { + throw new Error(`Source directory ${source} does not exist.`); + } + + // Create target directory if it does not exist + if (!system.directoryExists(target)) { + system.createDirectory(target); + } + + system.readDirectory(source).forEach(file => { + if (system.directoryExists(file)) { + copyDirectory(system, file, target, kind); + } else { + const addonName = source.substring(source.lastIndexOf("/")); + copyFile(system, addonName, file, target, kind); + } + }); +}; + +const copyFile = (system: ts.System, subDirName: string, source: string, target: string, kind: "project" | "addon") => { + const fileContent = system.readFile(source); + if (typeof fileContent === "string") { + // Create a new file with the same path relative to `buildDir` + const targetPath = join(target, source.substring(source.indexOf(subDirName) + (kind === "project" ? subDirName.length + 1 : 0))); + system.writeFile(targetPath, fileContent); + } +}; diff --git a/packages/testing/src/compilation/copy.ts b/packages/testing/src/compilation/copy.ts deleted file mode 100644 index 55809dc1..00000000 --- a/packages/testing/src/compilation/copy.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { basename, join } from "path"; -import ts from "typescript"; - -const copyFileSync = (system: ts.System, source: string, target: string) => { - let targetFile = target; - // If target is a directory, a new file with the same name will be created - if (system.directoryExists(target)) { - targetFile = join(target, basename(source)); - } - const fileContent = system.readFile(source); - if (fileContent) { - system.writeFile(targetFile, fileContent); - } -}; - -export const copyFolderSync = (system: ts.System, source: string, target: string) => { - let files = []; - // Check if folder needs to be created or integrated - const targetFolder = join(target, basename(source)); - if (!system.directoryExists(targetFolder)) { - system.createDirectory(targetFolder); - } - // Copy - if (system.directoryExists(source)) { - files = system.readDirectory(source); - files.forEach(file => { - if (system.directoryExists(file)) { - copyFolderSync(system, file, targetFolder); - } else { - copyFileSync(system, file, targetFolder); - } - }); - } -}; diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index 3f117aba..c76faa65 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -4,25 +4,40 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import ts from "typescript"; import { compilationEnv } from "./environment"; +import { resolve } from "path"; describe("compilationEnv", () => { it("should yield default configuration with defaults", () => { - const testObj = compilationEnv("expected"); + const testObj = compilationEnv("/expected"); - expect(testObj.getRootDir().endsWith("/expected")).toBe(true); - expect(testObj.getCompiler()).toBeDefined(); expect(testObj.isVirtual()).toBe(true); + expect(testObj.getRootDir()).toBe("/expected"); + expect(testObj.getAddonsDir()).toBe("/expected/addons"); + expect(testObj.getCompiler()).toBeDefined(); expect(testObj.getSystem()).toBeDefined(); expect(testObj.getSystem().useCaseSensitiveFileNames).toBe(false); }); + it("should yield configuration with non-virtual system", () => { + const testObj = compilationEnv("./expected", { virtual: false }); + + expect(testObj.isVirtual()).toBe(false); + expect(testObj.getRootDir()).toBe(resolve("./expected")); + expect(testObj.getAddonsDir()).toBe(resolve(testObj.getRootDir(), "./addons")); + expect(testObj.getCompiler()).toBeDefined(); + expect(testObj.getSystem()).toEqual(ts.sys); + expect(testObj.getSystem().useCaseSensitiveFileNames).toBe(ts.sys.useCaseSensitiveFileNames); + + testObj.cleanUp(); + }); + it("should yield default compiler options with defaults", () => { const testObj = compilationEnv("/target"); const actual = testObj.getCompilerOptions(); expect(actual).toMatchObject({ - buildDir: "/target", + buildDir: "/target/src", project: { configFilePath: "./tsconfig.json", module: ts.ModuleKind.ESNext, @@ -40,17 +55,17 @@ describe("compilationEnv", () => { }); it("should yield custom compiler options with custom overrides", () => { - const testObj = compilationEnv("/target", { compilerOptions: { buildDir: "/expected-src", project: { outDir: "/expected-out" } } }); + const testObj = compilationEnv("/target", { compilerOptions: { buildDir: "./expected-src", project: { outDir: "./expected-out" } } }); const actual = testObj.getCompilerOptions(); expect(actual).toMatchObject({ - buildDir: "/expected-src", + buildDir: "./expected-src", project: { configFilePath: "./tsconfig.json", module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ESNext, - outDir: "/expected-out", + outDir: "./expected-out", }, }); }); @@ -60,56 +75,45 @@ describe("compilationEnv#addons", () => { it("should yields no addons with defaults", () => { const testObj = compilationEnv("/target"); - const actual = testObj.getAddons(); - - expect(actual.getAddonDir()).toBe("/target/addons"); - expect(actual.getAvailableAddons()).toEqual([]); + expect(testObj.getAddonsDir()).toBe("/target/addons"); + expect(testObj.getActiveAddons()).toEqual([]); }); it("should yield addon with valid addon source", () => { - const testObj = compilationEnv("/target").addAddon("expected-addon", `export const activate = () => {};`); + const testObj = compilationEnv("/target").addAddon("expected-addon", { "addon.ts": `export const activate = () => {};` }); - const actual = testObj - .getAddons() - .getAvailableAddons() - .map(it => it?.name); + const actual = testObj.getActiveAddons().map(it => it?.name); expect(actual).toEqual(["expected-addon"]); }); it("should yield no addons with invalid addon source", () => { - const testObj = compilationEnv("/target").addAddon("invalid-addon", `export const NO_ACTIVATE_FUNCTION = true;`); + const testObj = compilationEnv("/target").addAddon("invalid-addon", { "addon.ts": `export const NO_ACTIVATE_FUNCTION = true;` }); - const actual = testObj.getAddons().getAvailableAddons(); + const actual = testObj.getActiveAddons(); expect(actual).toHaveLength(0); }); it("should yield addon with single addon in default addons path", () => { const testObj = compilationEnv("/target"); - testObj.getSystem().writeFile("/test-data/addons/expected-addon/addon.ts", `export const activate = () => {};`); + testObj.getSystem().writeFile("/addons/expected-addon/addon.ts", `export const activate = () => {};`); - testObj.addAddons(["expected-addon"]); + testObj.addAddon("expected-addon"); - const actual = testObj - .getAddons() - .getAvailableAddons() - .map(it => it?.name); + const actual = testObj.getActiveAddons().map(it => it?.name); expect(actual).toEqual(["expected-addon"]); }); it("should yield addons with multiple addons in default addons path", () => { const testObj = compilationEnv("/target"); - testObj.getSystem().writeFile("/test-data/addons/expected-addon1/addon.ts", `export const activate = () => {};`); - testObj.getSystem().writeFile("/test-data/addons/expected-addon2/addon.ts", `export const activate = () => {};`); + testObj.getSystem().writeFile("/addons/expected-addon1/addon.ts", `export const activate = () => {};`); + testObj.getSystem().writeFile("/addons/expected-addon2/addon.ts", `export const activate = () => {};`); testObj.addAddons(["expected-addon1", "expected-addon2"]); - const actual = testObj - .getAddons() - .getAvailableAddons() - .map(it => it?.name); + const actual = testObj.getActiveAddons().map(it => it?.name); expect(actual).toEqual(["expected-addon1", "expected-addon2"]); }); @@ -121,209 +125,175 @@ describe("compilationEnv#addons", () => { testObj.addAddons(["expected-addon1", "expected-addon2"], "./custom-addons-folder/"); - const actual = testObj - .getAddons() - .getAvailableAddons() - .map(it => it?.name); + const actual = testObj.getActiveAddons().map(it => it?.name); expect(actual).toEqual(["expected-addon1", "expected-addon2"]); }); }); describe("compilationEnv#projects", () => { - it("should yield empty project with defaults", () => { - const testObj = compilationEnv("/target").addProject("expected-project"); + it("should yield empty project with non-existing path", () => { + const testObj = compilationEnv("/target").setupProjectFromDisk("/does-not-exist"); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toHaveLength(0); + expect(actual).toEqual([]); }); - it("should yield project with project files and file names", () => { - const testObj = compilationEnv("/target"); - testObj.addProject("expected-project", { "index.ts": `export * from "./target";`, "target.ts": `export class Target {}` }); + it("should yield project with project source and file names", () => { + const testObj = compilationEnv("/target").setupProjectFromSource({ + "index.ts": `export * from "./target";`, + "target.ts": `export class Target {}`, + }); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); + expect(actual.map(it => it.getContent())).toEqual([`export * from "./target";`, `export class Target {}`]); }); - it("should yield project with project files and relative paths", () => { - const testObj = compilationEnv("/target"); - testObj.addProject("expected-project", { - "./foo-bar/index.ts": `export * from "./target";`, - "./foo-bar/target.ts": `export class Target {}`, + it("should yield project with project source and relative paths", () => { + const testObj = compilationEnv("/target").setupProjectFromSource({ + "./expected/index.ts": `export * from "./target";`, + "./expected/target.ts": `export class Target {}`, }); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/foo-bar/index.ts", "/target/expected-project/foo-bar/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/expected/index.ts", "/target/src/expected/target.ts"]); }); - it("should yield project with project files and relative project paths", () => { - const testObj = compilationEnv("/target"); - testObj.addProject("expected-project", { - "./expected-project/index.ts": `export * from "./target";`, - "./expected-project/target.ts": `export class Target {}`, + it("should yield project with project source and relative src paths", () => { + const testObj = compilationEnv("/target").setupProjectFromSource({ + "./src/index.ts": `export * from "./target";`, + "./src/target.ts": `export class Target {}`, }); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); }); - it("should yield project with project files and absolute paths", () => { - const testObj = compilationEnv("/target"); - testObj.addProject("expected-project", { - "/target/expected-project/index.ts": `export * from "./target";`, - "/target/expected-project/target.ts": `export class Target {}`, + it("should yield project with project source and absolute paths", () => { + const testObj = compilationEnv("/target").setupProjectFromSource({ + "/target/src/index.ts": `export * from "./target";`, + "/target/src/target.ts": `export class Target {}`, }); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); }); it("should yield empty project with invalid absolute paths", () => { - const testObj = compilationEnv("/target"); - testObj.addProject("expected-project", { + const testObj = compilationEnv("/target").setupProjectFromSource({ // buildDir is missing in absolute paths - "/expected-project/index.ts": `export * from "./target";`, - "/expected-project/target.ts": `export class Target {}`, + "/whatever-path/index.ts": `export * from "./target";`, + "/whatever-path/target.ts": `export class Target {}`, }); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toHaveLength(0); + expect(actual).toEqual([]); + expect(testObj.getSystem().readFile("/whatever-path/index.ts")).toBe(`export * from "./target";`); + expect(testObj.getSystem().readFile("/whatever-path/target.ts")).toBe(`export class Target {}`); }); it("should yield project with single project in default projects path", () => { const testObj = compilationEnv("/target"); - testObj.getSystem().writeFile("/test-data/projects/expected-project/index.ts", `export * from "./target";`); - testObj.getSystem().writeFile("/test-data/projects/expected-project/target.ts", `export class Target {}`); + testObj.getSystem().writeFile("/test-projects/expected-project/src/index.ts", `export * from "./target";`); + testObj.getSystem().writeFile("/test-projects/expected-project/src/target.ts", `export class Target {}`); + testObj.getSystem().writeFile("/test-projects/expected-project/tsconfig.json", `{}`); - testObj.addProject("expected-project"); + testObj.setupProjectFromDisk("expected-project"); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts", "/target/tsconfig.json"]); }); it("should yield projects with multiple projects in default projects path", () => { const testObj = compilationEnv("/target"); - testObj.getSystem().writeFile("/test-data/projects/expected-project1/index.ts", `export * from "./one";`); - testObj.getSystem().writeFile("/test-data/projects/expected-project1/one.ts", `export class One {}`); - testObj.getSystem().writeFile("/test-data/projects/expected-project2/index.ts", `export * from "./two";`); - testObj.getSystem().writeFile("/test-data/projects/expected-project2/two.ts", `export class Two {}`); + testObj.getSystem().writeFile("/test-projects/expected-project1/src/index.ts", `export * from "./one";`); + testObj.getSystem().writeFile("/test-projects/expected-project1/src/one.ts", `export class One {}`); + testObj.getSystem().writeFile("/test-projects/expected-project2/src/index.ts", `export * from "./two";`); + testObj.getSystem().writeFile("/test-projects/expected-project2/src/two.ts", `export class Two {}`); - testObj.addProject("expected-project1").addProject("expected-project2"); + testObj.setupProjectFromDisk("expected-project1").setupProjectFromDisk("expected-project2"); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(2); - expect(actual[0].getPath()).toBe("/target/expected-project1"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project1/index.ts", "/target/expected-project1/one.ts"]); - expect(actual[1].getPath()).toBe("/target/expected-project2"); - expect(actual[1].getFiles()).toEqual(["/target/expected-project2/index.ts", "/target/expected-project2/two.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/one.ts", "/target/src/two.ts"]); + expect(actual.map(it => it.getContent())).toEqual([`export * from "./two";`, `export class One {}`, `export class Two {}`]); }); it("should yield project with single project in custom projects path", () => { const testObj = compilationEnv("/target"); - testObj.getSystem().writeFile("/custom-projects/expected-project/index.ts", `export * from "./target";`); - testObj.getSystem().writeFile("/custom-projects/expected-project/target.ts", `export class Target {}`); + testObj.getSystem().writeFile("/custom-projects/expected-project/src/index.ts", `export * from "./target";`); + testObj.getSystem().writeFile("/custom-projects/expected-project/src/target.ts", `export class Target {}`); + testObj.getSystem().writeFile("/custom-projects/expected-project/tsconfig.json", `{}`); - testObj.addProject("expected-project", "../custom-projects/"); + testObj.setupProjectFromDisk("expected-project", "../custom-projects/"); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts", "/target/tsconfig.json"]); }); it("should yield project and add file with file name", () => { - const testObj = compilationEnv("/target").addProject("expected-project"); - - testObj.getProject("expected-project")!.addFile("index.ts", `export * from "./target";`).addFile("target.ts", `export class Target {}`); + const testObj = compilationEnv("/target") + .setupProjectFromDisk("expected-project") + .addProjectFile("index.ts", `export * from "./target";`) + .addProjectFile("target.ts", `export class Target {}`); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); + expect(actual.map(it => it.getContent())).toEqual([`export * from "./target";`, `export class Target {}`]); }); it("should yield project and add files with relative paths", () => { - const testObj = compilationEnv("/target").addProject("expected-project"); + const testObj = compilationEnv("/target") + .setupProjectFromDisk("expected-project") + .addProjectFile("./expected-dir/index.ts", `export * from "./target";`) + .addProjectFile("./expected-dir/target.ts", `export class Target {}`); - testObj - .getProject("expected-project")! - .addFile("./foo-bar/index.ts", `export * from "./target";`) - .addFile("./foo-bar/target.ts", `export class Target {}`); + const actual = testObj.getProjectFiles(); - const actual = testObj.getProjects(); - - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/foo-bar/index.ts", "/target/expected-project/foo-bar/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/expected-dir/index.ts", "/target/src/expected-dir/target.ts"]); }); - it("should yield project and add files with relative project paths", () => { - const testObj = compilationEnv("/target").addProject("expected-project"); - - testObj - .getProject("expected-project")! - .addFile("./expected-project/index.ts", `export * from "./target";`) - .addFile("./expected-project/target.ts", `export class Target {}`); + it("should yield project and add files with relative src paths", () => { + const testObj = compilationEnv("/target") + .setupProjectFromDisk("expected-project") + .addProjectFile("./src/index.ts", `export * from "./target";`) + .addProjectFile("./src/target.ts", `export class Target {}`); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); }); it("should yield project and add files with absolute paths", () => { - const testObj = compilationEnv("/target").addProject("expected-project"); + const testObj = compilationEnv("/target") + .setupProjectFromDisk("expected-project") + .addProjectFile("/target/expected-project/index.ts", `export * from "./target";`) + .addProjectFile("/target/expected-project/target.ts", `export class Target {}`); - testObj - .getProject("expected-project")! - .addFile("/target/expected-project/index.ts", `export * from "./target";`) - .addFile("/target/expected-project/target.ts", `export class Target {}`); + const actual = testObj.getProjectFiles(); - const actual = testObj.getProjects(); - - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + expect(actual.map(it => it.getPath())).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); }); it("should yield empty project with invalid absolute paths added", () => { - const testObj = compilationEnv("/target").addProject("expected-project"); - - testObj - .getProject("expected-project")! - .addFile("/expected-project/index.ts", `export * from "./target";`) - .addFile("/expected-project/target.ts", `export class Target {}`); + const testObj = compilationEnv("/target") + .setupProjectFromDisk("expected-project") + .addProjectFile("/expected-project/index.ts", `export * from "./target";`) + .addProjectFile("/expected-project/target.ts", `export class Target {}`); - const actual = testObj.getProjects(); + const actual = testObj.getProjectFiles(); - expect(actual).toHaveLength(1); - expect(actual[0].getPath()).toBe("/target/expected-project"); - expect(actual[0].getFiles()).toHaveLength(0); + expect(actual).toEqual([]); + expect(testObj.getSystem().readDirectory("/")).toEqual(["/expected-project/index.ts", "/expected-project/target.ts"]); }); }); diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index b697e932..b14c34bd 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -1,27 +1,34 @@ -import { Compiler, CompilerOptions, createBrowserSystem } from "@quatico/websmith-core"; -import { basename, dirname, extname, isAbsolute } from "path"; +import { AddonRegistry, Compiler, createBrowserSystem, type CompilerAddon, type CompilerOptions } from "@quatico/websmith-core"; +import { basename, dirname, extname, isAbsolute, join } from "path"; import requireFromString from "require-from-string"; import ts from "typescript"; import { compileOptions } from "../compile-options"; -import { copyFolderSync } from "./copy"; +import { copyDirectory } from "./copy-directory"; import { resolvePath } from "./resolve-path"; +const DEFAULT_ROOT_DIR = "/"; +const DEFAULT_BUILD_DIR = "./src"; +const DEFAULT_PROJECTS_SOURCE_DIR = "../test-projects"; +const DEFAULT_ADDONS_SOURCE_DIR = "../addons"; + export class CompilationEnv { private compiler: Compiler; private rootDir: string; + private buildDir: string; private system: ts.System; private virtual: boolean; - constructor(rootDir: string, options?: CompilationOptions) { + constructor(rootDir?: string, options?: CompilationOptions) { const { virtual = true, compilerOptions = {}, useCaseSensitiveFileNames, files } = options ?? {}; this.virtual = virtual; this.system = this.virtual ? createBrowserSystem(files, useCaseSensitiveFileNames) : ts.sys; - this.rootDir = resolvePath(this.system, rootDir); + this.rootDir = resolvePath(this.system, rootDir ?? DEFAULT_ROOT_DIR); + this.buildDir = resolvePath(this.system, this.rootDir, options?.compilerOptions?.buildDir ?? DEFAULT_BUILD_DIR); this.addFiles(files); - const compOptions = compileOptions(this.system, { buildDir: this.rootDir, ...compilerOptions }); - this.compileAddons(compOptions.addons.getAddonDir()); + const compOptions = compileOptions(this.system, { buildDir: this.buildDir, ...compilerOptions }); + this.compileAddons(compOptions.addons.getAddonsDir()); this.compiler = new Compiler(compOptions, this.system); @@ -30,6 +37,11 @@ export class CompilationEnv { } } + /** + * The working directory where project configuration files are stored. + * + * @returns absolute path to the working directory, defaults to "/". + */ public getRootDir(): string { return this.rootDir; } @@ -57,75 +69,119 @@ export class CompilationEnv { return this; } - public getAddons() { - return this.compiler.getOptions().addons; + /** + * The directory where active addons are moved to, for customizing the compilation. + * + * @returns absolute path to the addons directory, defaults to `${this.rootDir}/addons` + */ + public getAddonsDir(): string { + return this.getAddonRegistry().getAddonsDir(); } - public addAddon(addonName: string, addonCode: string): this { - this.addAddonFile(addonName, addonCode); - this.compileAddons(this.getAddons().getAddonDir()); - this.getAddons().refresh(); - return this; + public getActiveAddon(addonName: string): CompilerAddon | undefined { + return this.getAddonRegistry() + .getAvailableAddons() + .find(it => it.name === addonName); } - public addAddons(addonNames: string[], sourceDir = "../test-data/addons/"): this { - const addonsDir = resolvePath(this.system, this.getAddons().getAddonDir()); - addonNames.forEach(addon => { - copyFolderSync(this.system, resolvePath(this.system, this.rootDir, sourceDir, addon), addonsDir); - }); - this.compileAddons(this.getAddons().getAddonDir()); - this.getAddons().refresh(); - - return this; + public getActiveAddons(): CompilerAddon[] { + return this.getAddonRegistry().getAvailableAddons(); } - public getProject(projectName: string): Project | undefined { - const buildDir = this.getCompilerOptions().buildDir; - const projectDir = this.system.getDirectories(buildDir).find(it => it === projectName); - if (projectDir) { - return new Project(resolvePath(this.system, buildDir, projectDir), this.system); - } - return undefined; - } - - public getProjects(): Project[] { - const buildDir = this.getCompilerOptions().buildDir; - const projectDirs = this.system.getDirectories(buildDir); - return projectDirs.map(it => resolvePath(this.system, buildDir, it)).map(it => new Project(it, this.system)); - } + /** + * Installs addon source code from `addonsSourceDir` or provided `source` parameter into + * the addons directory, i.e. `${this.rootDir}/addons`. It compiles the addon source code + * and refreshes the addons registry to activate it. + * + * @param addonName directory name of the addon + * @param addonSource optional source files or path to the source directory to install + * @returns this instance + */ + public addAddon(addonName: string, addonSource?: string | Record): this { + const addonTargetPath = join(this.getAddonsDir(), addonName); - public addProject(projectName: string, source?: string | Record): this { - const isFiles = (source?: string | Record): source is Record => typeof source === "object"; - const projectPath = resolvePath(this.system, this.rootDir, projectName); - - if (!this.system.directoryExists(projectPath)) { - this.system.createDirectory(projectPath); + if (!this.system.directoryExists(addonTargetPath)) { + this.system.createDirectory(addonTargetPath); } - if (isFiles(source)) { + if (isFiles(addonSource)) { this.addFiles( - Object.entries(source).reduce((acc: Record, [filePath, content]) => { + Object.entries(addonSource).reduce((acc: Record, [filePath, content]) => { if (isAbsolute(filePath)) { acc[filePath] = content; } else { - if (filePath.includes(projectName)) { - acc[resolvePath(this.system, this.rootDir, filePath)] = content; + if (filePath.includes(addonName)) { + acc[join(this.getAddonsDir(), filePath)] = content; } else { - acc[resolvePath(this.system, this.rootDir, projectName, filePath)] = content; + acc[join(addonTargetPath, filePath)] = content; } } return acc; }, {}) ); } else { - const sourceDir = source ?? "../test-data/projects/"; - const projectDir = resolvePath(this.system, this.rootDir, sourceDir, projectName); - copyFolderSync(this.system, projectDir, this.getCompilerOptions().buildDir); + const addonsSourceDir = resolvePath(this.system, this.rootDir, addonSource ?? DEFAULT_ADDONS_SOURCE_DIR, addonName); + copyDirectory(this.system, addonsSourceDir, addonTargetPath, "addon"); } + + this.compileAddons(this.getAddonRegistry().getAddonsDir()); + this.getAddonRegistry().refresh(); + return this; + } + + public addAddons(addonNames: string[], addonsSourceDir?: string): this { + const addonsDir = this.getAddonsDir(); + const addonsSourceDirPath = resolvePath(this.system, this.rootDir, addonsSourceDir ?? DEFAULT_ADDONS_SOURCE_DIR); + addonNames.forEach(addon => { + copyDirectory(this.system, join(addonsSourceDirPath, addon), addonsDir, "addon"); + }); + this.compileAddons(addonsDir); + this.getAddonRegistry().refresh(); + return this; } - private addAddonFile(addonName: string, addonCode: string) { - this.system.writeFile(resolvePath(this.system, this.getAddons().getAddonDir(), addonName, "addon.ts"), addonCode); + /** + * Installs project source code from provided `source` parameter into the + * build directory, i.e. `this.buildDir`. + * + * @param source optional source files to install + * @returns this instance + */ + public setupProjectFromSource(source: Record): this { + this.addFiles( + Object.entries(source).reduce((acc: Record, [filePath, content]) => { + acc[resolveProjectPath(this.system, this.buildDir, filePath)] = content; + return acc; + }, {}) + ); + return this; + } + + /** + * Installs project source code form default `projectsSourceDir` or provided `projectsSourceDir` parameter into the + * build directory, i.e. `this.buildDir`. + * + * @param projectName name of the project directory to install + * @param projectsSourceDir optional path to the source directory to install + * @returns this instance + */ + public setupProjectFromDisk(projectName: string, projectsSourceDir?: string): this { + const projectsSourcePath = resolvePath(this.system, this.rootDir, projectsSourceDir ?? DEFAULT_PROJECTS_SOURCE_DIR); + copyDirectory(this.system, join(projectsSourcePath, projectName), this.rootDir, "project"); + return this; + } + + public addProjectFile(relativePath: string, content: string): this { + this.system.writeFile(resolveProjectPath(this.system, this.buildDir, relativePath), content); + return this; + } + + public getProjectFiles(): ProjectFile[] { + return this.system.readDirectory(this.rootDir).map(it => projectFile(this.system, this.buildDir, it)); + } + + public compile(): ts.EmitResult { + return this.compiler.compile(); } private compileAddons(addonsDir: string) { @@ -162,7 +218,7 @@ export class CompilationEnv { } } - private addFiles(files?: Record) { + private addFiles(files?: Record): void { if (!files) { return; } @@ -170,6 +226,10 @@ export class CompilationEnv { this.system.writeFile(file, files[file]); }); } + + private getAddonRegistry(): AddonRegistry { + return this.compiler.getOptions().addons; + } } export type CompilationOptions = { @@ -178,37 +238,31 @@ export type CompilationOptions = { useCaseSensitiveFileNames?: boolean; virtual?: boolean; }; -export class Project { - private path: string; - private system: ts.System; - constructor(path: string, system: ts.System) { - this.path = path; - this.system = system; - } +export interface ProjectFile { + getPath(): string; + getContent(): string | undefined; +} - public getPath(): string { - return this.path; - } +export const projectFile = (system: ts.System, buildDir: string, relativePath: string): ProjectFile => ({ + getPath: () => resolveProjectPath(system, buildDir, relativePath), + getContent: () => system.readFile(resolveProjectPath(system, buildDir, relativePath)), +}); - public addFile(filePath: string, content: string): this { - let path; - if (isAbsolute(filePath)) { - path = resolvePath(this.system, filePath); +const resolveProjectPath = (system: ts.System, buildDir: string, relativePath: string) => { + let filePath; + if (isAbsolute(relativePath)) { + filePath = resolvePath(system, relativePath); + } else { + if (relativePath.includes(basename(buildDir))) { + filePath = resolvePath(system, dirname(buildDir), relativePath); } else { - if (filePath.includes(basename(this.path))) { - path = resolvePath(this.system, dirname(this.path), filePath); - } else { - path = resolvePath(this.system, this.path, filePath); - } + filePath = resolvePath(system, buildDir, relativePath); } - this.system.writeFile(path, content); - return this; } + return filePath; +}; - public getFiles(): string[] { - return this.system.readDirectory(this.path); - } -} +const isFiles = (source?: string | Record): source is Record => typeof source === "object"; export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => new CompilationEnv(rootDir, options); diff --git a/packages/testing/src/compile-options.ts b/packages/testing/src/compile-options.ts index 7c3e9159..f3d69eda 100644 --- a/packages/testing/src/compile-options.ts +++ b/packages/testing/src/compile-options.ts @@ -9,15 +9,19 @@ import ts from "typescript"; import { ReporterMock } from "./ReporterMock"; import { resolvePath } from "./compilation/resolve-path"; +const DEFAULT_BUILD_DIR = "./src"; +const DEFAULT_ADDONS_DIR = "../addons"; + export const compileOptions = ( system: ts.System, // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents overrides?: Partial & { tsconfig?: Partial; project?: Partial; targets?: string[] } ): CompilerOptions => { const reporter = new ReporterMock(system); - const buildDir: string = resolvePath(system, overrides?.buildDir ?? "./src"); + const buildDir: string = resolvePath(system, overrides?.buildDir ?? DEFAULT_BUILD_DIR); + const addonsDirPath = resolvePath(system, buildDir, DEFAULT_ADDONS_DIR); return { - addons: new AddonRegistry({ addonsDir: resolvePath(system, buildDir, "./addons"), reporter, system }), + addons: new AddonRegistry({ addonsDir: addonsDirPath, reporter, system }), buildDir, reporter, debug: false, diff --git a/packages/webpack/src/options.spec.ts b/packages/webpack/src/options.spec.ts index 91250e8a..16f73d2e 100644 --- a/packages/webpack/src/options.spec.ts +++ b/packages/webpack/src/options.spec.ts @@ -36,7 +36,7 @@ describe("createOptions", () => { it("should return expected path w/ custom addons directory", () => { const { fileSystem: target } = compileSystem({ "./tsconfig.json": "{}", - "./expected/addon-foo/addon.ts": "export const activate = () => {};", + "./expected/addon-foo/addon.js": "export const activate = () => {};", }); jest.mock( "/expected/addon-foo/addon", @@ -46,7 +46,7 @@ describe("createOptions", () => { { virtual: true } ); - const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.getAddons(); + const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.getAvailableAddons(); expect(actual.map(it => it.name)).toEqual(["addon-foo"]); }); @@ -77,7 +77,7 @@ describe("createOptions", () => { it("should return config w/ valid addonsDir, addons in compiler config json", () => { const { fileSystem: target } = compileSystem({ "./tsconfig.json": "{}", - "/expected/one/addon.ts": "export const activate = () => {};", + "/expected/one/addon.js": "export const activate = () => {};", "websmith.config.json": '{ "addons":["one", "two"], "addonsDir":"./expected" }', }); jest.mock( @@ -90,28 +90,16 @@ describe("createOptions", () => { const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).addons; - expect(actual).toMatchInlineSnapshot(` - AddonRegistry { - "addons": [ - "one", - "two", - ], - "availableAddons": Map { - "one" => { - "activate": [MockFunction], - "name": "one", - }, - }, - "config": { - "addons": [ - "one", - "two", - ], - "addonsDir": "/expected", - "configFilePath": "/websmith.config.json", - }, - "reporter": NoReporter {}, - } - `); + expect(actual).toMatchObject({ + addons: ["one", "two"], + availableAddons: new Map( + Object.entries({ + one: { + activate: expect.any(Function), + name: "one", + }, + }) + ), + }); }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 17eb914d..47e94758 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -429,13 +429,6 @@ importers: version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) packages/test: - dependencies: - '@types/require-from-string': - specifier: ^1.2.3 - version: 1.2.3 - require-from-string: - specifier: ^2.0.2 - version: 2.0.2 devDependencies: '@eslint/js': specifier: ^9.1.1 @@ -443,9 +436,6 @@ importers: '@nx/eslint-plugin': specifier: ^18.3.3 version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) - '@quatico/websmith-api': - specifier: workspace:^ - version: link:../api '@quatico/websmith-compiler': specifier: workspace:^ version: link:../compiler From e6a7df11263ff9952916a69881ffdbfe066c2932 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Wed, 1 May 2024 22:04:28 +0200 Subject: [PATCH 10/52] e Aligns package dependencies and test aliases --- packages/examples/jest.config.js | 2 +- packages/examples/package.json | 2 +- packages/test/jest.config.js | 1 + packages/testing/jest.config.js | 3 +-- packages/webpack-test/jest.config.js | 3 --- packages/webpack-test/package.json | 2 -- packages/webpack/jest.config.js | 1 - pnpm-lock.yaml | 10 ++-------- 8 files changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/examples/jest.config.js b/packages/examples/jest.config.js index 3e7bfd16..e5b18449 100644 --- a/packages/examples/jest.config.js +++ b/packages/examples/jest.config.js @@ -11,7 +11,7 @@ module.exports = { moduleFileExtensions: ["ts", "js", "json", "node"], moduleNameMapper: { "@quatico/websmith-api": "/../api/src", - "@quatico/websmith-core": "/../core/src", + "@quatico/websmith-testing": "/../testing/src", }, testRegex: "src/.*spec\\.(js|ts)$", setupFilesAfterEnv: ["/../../jest.setup.ts"], diff --git a/packages/examples/package.json b/packages/examples/package.json index ee50d71c..352e1ec9 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -21,7 +21,7 @@ "@eslint/js": "^9.1.1", "@nx/eslint-plugin": "^18.3.3", "@quatico/websmith-api": "workspace:^", - "@quatico/websmith-core": "workspace:^", + "@quatico/websmith-testing": "workspace:^", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", diff --git a/packages/test/jest.config.js b/packages/test/jest.config.js index f87f72c8..bc540fe0 100644 --- a/packages/test/jest.config.js +++ b/packages/test/jest.config.js @@ -10,6 +10,7 @@ module.exports = { moduleNameMapper: { "@quatico/websmith-core": "/../core/src", "@quatico/websmith-compiler": "/../compiler/src", + "@quatico/websmith-testing": "/../testing/src", }, prettierPath: null, roots: ["/src/"], diff --git a/packages/testing/jest.config.js b/packages/testing/jest.config.js index 85ec29b4..0356b1da 100644 --- a/packages/testing/jest.config.js +++ b/packages/testing/jest.config.js @@ -1,5 +1,3 @@ -const { prettierPath } = require("../../jest.config"); - /* * --------------------------------------------------------------------------------------------- * Copyright (c) Quatico Solutions AG. All rights reserved. @@ -13,6 +11,7 @@ module.exports = { moduleFileExtensions: ["ts", "js", "json", "node"], moduleNameMapper: { "@quatico/websmith-core": "/../core/src", + "@quatico/websmith-testing": "/../testing/src", }, prettierPath: null, testRegex: "src/.*spec\\.(js|ts)$", diff --git a/packages/webpack-test/jest.config.js b/packages/webpack-test/jest.config.js index 1f65be18..cfb33128 100644 --- a/packages/webpack-test/jest.config.js +++ b/packages/webpack-test/jest.config.js @@ -9,10 +9,7 @@ module.exports = { roots: ["/src/"], moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], moduleNameMapper: { - "@quatico/websmith-api": "/../api/src", - "@quatico/websmith-core": "/../core/src", "@quatico/websmith-webpack": "/../webpack/src", - "@quatico/websmith-testing": "/../testing/src", }, testEnvironment: "node", testRegex: ".+\\.test\\.ts", diff --git a/packages/webpack-test/package.json b/packages/webpack-test/package.json index 4ccc8d03..edc9c512 100644 --- a/packages/webpack-test/package.json +++ b/packages/webpack-test/package.json @@ -16,8 +16,6 @@ "devDependencies": { "@eslint/js": "^9.1.1", "@nx/eslint-plugin": "^18.3.3", - "@quatico/websmith-api": "workspace:^", - "@quatico/websmith-core": "workspace:^", "@quatico/websmith-webpack": "workspace:^", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", diff --git a/packages/webpack/jest.config.js b/packages/webpack/jest.config.js index 84e3cb91..a5c989e2 100644 --- a/packages/webpack/jest.config.js +++ b/packages/webpack/jest.config.js @@ -10,7 +10,6 @@ module.exports = { coverageDirectory: "coverage", moduleNameMapper: { "@quatico/websmith-api": "/../api/src", - "@quatico/websmith-compiler": "/../compiler/src", "@quatico/websmith-core": "/../core/src", "@quatico/websmith-testing": "/../testing/src", }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 47e94758..3d1a5bef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -367,9 +367,9 @@ importers: '@quatico/websmith-api': specifier: workspace:^ version: link:../api - '@quatico/websmith-core': + '@quatico/websmith-testing': specifier: workspace:^ - version: link:../core + version: link:../testing '@swc/core': specifier: 1.5.0 version: 1.5.0 @@ -687,12 +687,6 @@ importers: '@nx/eslint-plugin': specifier: ^18.3.3 version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) - '@quatico/websmith-api': - specifier: workspace:^ - version: link:../api - '@quatico/websmith-core': - specifier: workspace:^ - version: link:../core '@quatico/websmith-webpack': specifier: workspace:^ version: link:../webpack From 240068ef576fad455ee9a3e4e6b9f5c93630d7c6 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Wed, 1 May 2024 22:10:43 +0200 Subject: [PATCH 11/52] a Fixes automatic linting issues --- packages/testing/jest.config.js | 1 + packages/testing/src/compilation/environment.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/testing/jest.config.js b/packages/testing/jest.config.js index 0356b1da..fb935a6e 100644 --- a/packages/testing/jest.config.js +++ b/packages/testing/jest.config.js @@ -10,6 +10,7 @@ module.exports = { coveragePathIgnorePatterns: ["index.ts"], moduleFileExtensions: ["ts", "js", "json", "node"], moduleNameMapper: { + "@quatico/websmith-api": "/../api/src", "@quatico/websmith-core": "/../core/src", "@quatico/websmith-testing": "/../testing/src", }, diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index b14c34bd..a269079d 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -78,10 +78,11 @@ export class CompilationEnv { return this.getAddonRegistry().getAddonsDir(); } + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents public getActiveAddon(addonName: string): CompilerAddon | undefined { return this.getAddonRegistry() .getAvailableAddons() - .find(it => it.name === addonName); + .find((it: CompilerAddon) => it.name === addonName); } public getActiveAddons(): CompilerAddon[] { From 708d0ec507cb1f4e9d6c04ef64ec05a7f0406252 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Wed, 1 May 2024 22:16:15 +0200 Subject: [PATCH 12/52] F Provides getProjectFile function --- packages/test/src/test-examples/bar-addon.test.ts | 4 ++-- packages/testing/src/compilation/environment.ts | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/test/src/test-examples/bar-addon.test.ts b/packages/test/src/test-examples/bar-addon.test.ts index 27fbaa46..4ae4e691 100644 --- a/packages/test/src/test-examples/bar-addon.test.ts +++ b/packages/test/src/test-examples/bar-addon.test.ts @@ -18,11 +18,11 @@ describe("test-project-foo", () => { ` export const foo = () => { console.log("foo"); - }; + };p ` ); - const actual = testObj.getProjectFile("foo.ts"); + const actual = testObj.getProjectFile("foo.ts")!.getContent(); expect(actual).toMatchInlineSnapshot( ` diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index a269079d..9e75a74e 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -181,6 +181,14 @@ export class CompilationEnv { return this.system.readDirectory(this.rootDir).map(it => projectFile(this.system, this.buildDir, it)); } + public getProjectFile(filePath: string): ProjectFile | undefined { + const file = this.system.readDirectory(this.rootDir).find(it => it.endsWith(filePath)); + if (file) { + return projectFile(this.system, this.buildDir, file); + } + return undefined; + } + public compile(): ts.EmitResult { return this.compiler.compile(); } From 28aae989a6f9bc5d4a716c4b14860d68a6bfa236 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 15:21:29 +0200 Subject: [PATCH 13/52] F Provides additional API for compiling a project and checking the results: + Add getCompiledFiles: returns all files in outDir + Add getCompiledFile: returns first matching file in outDir + Add getCompiledDir: returns absolute path to outDir + Add CompilationResults: with full access to the ts.EmitResult providing: * hasEmitSkipped: () => boolean; * getEmittedFiles: () => string[]; * hasFailures: () => boolean; * getFailureReport: (filter?: string) => string; * getDiagnostics: () => ts.Diagnostic[]; --- .../src/compilation/environment.spec.ts | 123 ++++++++++++++++-- .../testing/src/compilation/environment.ts | 104 +++++++++++---- packages/testing/src/compile-options.spec.ts | 32 +++++ packages/testing/src/compile-options.ts | 15 ++- 4 files changed, 241 insertions(+), 33 deletions(-) create mode 100644 packages/testing/src/compile-options.spec.ts diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index c76faa65..4367a8b2 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -2,9 +2,9 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import { resolve } from "path"; import ts from "typescript"; import { compilationEnv } from "./environment"; -import { resolve } from "path"; describe("compilationEnv", () => { it("should yield default configuration with defaults", () => { @@ -13,7 +13,8 @@ describe("compilationEnv", () => { expect(testObj.isVirtual()).toBe(true); expect(testObj.getRootDir()).toBe("/expected"); expect(testObj.getAddonsDir()).toBe("/expected/addons"); - expect(testObj.getCompiler()).toBeDefined(); + expect(testObj.getProjectDir()).toBe("/expected/src"); + expect(testObj.getCompiledDir()).toBe("/expected/dist"); expect(testObj.getSystem()).toBeDefined(); expect(testObj.getSystem().useCaseSensitiveFileNames).toBe(false); }); @@ -24,7 +25,8 @@ describe("compilationEnv", () => { expect(testObj.isVirtual()).toBe(false); expect(testObj.getRootDir()).toBe(resolve("./expected")); expect(testObj.getAddonsDir()).toBe(resolve(testObj.getRootDir(), "./addons")); - expect(testObj.getCompiler()).toBeDefined(); + expect(testObj.getProjectDir()).toBe(resolve(testObj.getRootDir(), "./src")); + expect(testObj.getCompiledDir()).toBe(resolve(testObj.getRootDir(), "./dist")); expect(testObj.getSystem()).toEqual(ts.sys); expect(testObj.getSystem().useCaseSensitiveFileNames).toBe(ts.sys.useCaseSensitiveFileNames); @@ -39,12 +41,12 @@ describe("compilationEnv", () => { expect(actual).toMatchObject({ buildDir: "/target/src", project: { - configFilePath: "./tsconfig.json", + configFilePath: "/target/tsconfig.json", module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ESNext, }, sourceMap: false, - targets: ["*"], + targets: [], transpileOnly: false, tsconfig: { errors: [], @@ -82,7 +84,7 @@ describe("compilationEnv#addons", () => { it("should yield addon with valid addon source", () => { const testObj = compilationEnv("/target").addAddon("expected-addon", { "addon.ts": `export const activate = () => {};` }); - const actual = testObj.getActiveAddons().map(it => it?.name); + const actual = testObj.getActiveAddons().map(it => it.name); expect(actual).toEqual(["expected-addon"]); }); @@ -101,7 +103,7 @@ describe("compilationEnv#addons", () => { testObj.addAddon("expected-addon"); - const actual = testObj.getActiveAddons().map(it => it?.name); + const actual = testObj.getActiveAddons().map(it => it.name); expect(actual).toEqual(["expected-addon"]); }); @@ -113,7 +115,7 @@ describe("compilationEnv#addons", () => { testObj.addAddons(["expected-addon1", "expected-addon2"]); - const actual = testObj.getActiveAddons().map(it => it?.name); + const actual = testObj.getActiveAddons().map(it => it.name); expect(actual).toEqual(["expected-addon1", "expected-addon2"]); }); @@ -125,7 +127,7 @@ describe("compilationEnv#addons", () => { testObj.addAddons(["expected-addon1", "expected-addon2"], "./custom-addons-folder/"); - const actual = testObj.getActiveAddons().map(it => it?.name); + const actual = testObj.getActiveAddons().map(it => it.name); expect(actual).toEqual(["expected-addon1", "expected-addon2"]); }); @@ -297,3 +299,106 @@ describe("compilationEnv#projects", () => { expect(testObj.getSystem().readDirectory("/")).toEqual(["/expected-project/index.ts", "/expected-project/target.ts"]); }); }); + +describe("compilationEnv#compiled", () => { + it("should yield no compiled files with empty project", () => { + const testObj = compilationEnv("/target"); + + const actual = testObj.getCompiledFiles(); + + expect(actual).toEqual([]); + }); + + it("should yield no compiled files with existing project but no compile", () => { + const testObj = compilationEnv("/target", { + files: { + "index.ts": `export * from './target';`, + "target.ts": `export class Target {}`, + }, + }); + + const actual = testObj.getCompiledFiles(); + + expect(actual).toEqual([]); + }); + + it("should yield no compiled files and empty result with empty project and compile", () => { + const testObj = compilationEnv("/target").compile(); + + expect(testObj.getCompiledFiles()).toEqual([]); + expect(testObj.hasEmitSkipped()).toBe(false); + expect(testObj.getEmittedFiles()).toEqual([]); + expect(testObj.getDiagnostics()).toEqual([]); + }); + + it("should yield compiled files with existing project and compile", () => { + const testObj = compilationEnv("/target", { + files: { + "index.ts": `export * from './target';`, + "target.ts": `export class Target {}`, + }, + }).compile(); + + expect(testObj.getCompiledFiles().map(it => it.getPath())).toEqual(["/target/dist/index.js", "/target/dist/target.js"]); + expect(testObj.hasEmitSkipped()).toBe(false); + expect(testObj.getEmittedFiles()).toEqual(["/target/dist/index.js", "/target/dist/target.js"]); + expect(testObj.getDiagnostics()).toEqual([]); + }); + + it("should yield compiled contents with existing project and compile", () => { + const testObj = compilationEnv("/target", { + files: { + "index.ts": `export * from './target';`, + "target.ts": `export class Target {}`, + }, + }).compile(); + + expect(testObj.getCompiledFile("/target/dist/index.js")!.getContent()).toBe(`export * from './target';\n`); + expect(testObj.getCompiledFile("/target/dist/target.js")!.getContent()).toBe(`export class Target {\n}\n`); + }); + + it("should yield compiled files with late project setup and compile", () => { + const testObj = compilationEnv("/target") + .setupProjectFromSource({ + "index.ts": `export * from './target';`, + "target.ts": `export class Target {}`, + }) + .compile(); + + const actual = testObj.getCompiledFiles(); + + expect(actual.map(it => it.getPath())).toEqual(["/target/dist/index.js", "/target/dist/target.js"]); + }); + + it("should yield compiled files with project", () => { + const testObj = compilationEnv("/target") + .setupProjectFromSource({ + "index.ts": `export * from './target';`, + "target.ts": `export class Target {}`, + }) + .compile(); + + expect(testObj.getCompiledFile("/target/dist/index.js")!.getContent()).toBe(`export * from './target';\n`); + expect(testObj.getCompiledFile("/target/dist/target.js")!.getContent()).toBe(`export class Target {\n}\n`); + }); + + it("should yield compilation errors with illegal project files", () => { + const testObj = compilationEnv("/target", { + compilerOptions: { project: { noEmitOnError: true } }, + files: { + "index.ts": `export * from './target';`, + "target.ts": `export ILLEGAL Target {};`, + }, + }).compile(); + + expect(testObj.getFailureReport("target.ts")).toMatchInlineSnapshot(` + "src/index.ts(1,15): error TS2306: File '/target/src/target.ts' is not a module. + src/target.ts(1,1): error TS1128: Declaration or statement expected. + src/target.ts(1,8): error TS1434: Unexpected keyword or identifier. + src/target.ts(1,16): error TS1434: Unexpected keyword or identifier. + src/target.ts(1,8): error TS2304: Cannot find name 'ILLEGAL'. + src/target.ts(1,16): error TS2304: Cannot find name 'Target'." + `); + expect(testObj.getEmittedFiles()).toEqual([]); + }); +}); diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 9e75a74e..c1192b3a 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -8,11 +8,12 @@ import { resolvePath } from "./resolve-path"; const DEFAULT_ROOT_DIR = "/"; const DEFAULT_BUILD_DIR = "./src"; +const DEFAULT_OUT_DIR = "./dist"; const DEFAULT_PROJECTS_SOURCE_DIR = "../test-projects"; const DEFAULT_ADDONS_SOURCE_DIR = "../addons"; export class CompilationEnv { - private compiler: Compiler; + private compilerOptions: CompilerOptions; private rootDir: string; private buildDir: string; private system: ts.System; @@ -21,20 +22,31 @@ export class CompilationEnv { constructor(rootDir?: string, options?: CompilationOptions) { const { virtual = true, compilerOptions = {}, useCaseSensitiveFileNames, files } = options ?? {}; this.virtual = virtual; - this.system = this.virtual ? createBrowserSystem(files, useCaseSensitiveFileNames) : ts.sys; + this.system = this.virtual ? createBrowserSystem(undefined, useCaseSensitiveFileNames) : ts.sys; this.rootDir = resolvePath(this.system, rootDir ?? DEFAULT_ROOT_DIR); this.buildDir = resolvePath(this.system, this.rootDir, options?.compilerOptions?.buildDir ?? DEFAULT_BUILD_DIR); - - this.addFiles(files); - - const compOptions = compileOptions(this.system, { buildDir: this.buildDir, ...compilerOptions }); - this.compileAddons(compOptions.addons.getAddonsDir()); - - this.compiler = new Compiler(compOptions, this.system); + const outDir = resolvePath(this.system, this.rootDir, options?.compilerOptions?.project?.outDir ?? DEFAULT_OUT_DIR); if (!this.system.directoryExists(this.rootDir)) { this.system.createDirectory(this.rootDir); } + this.system.getCurrentDirectory = () => this.rootDir; + + this.compilerOptions = compileOptions(this.system, { + buildDir: this.buildDir, + config: { + configFilePath: `${this.rootDir}/websmith.config.json`, + targets: { + "*": { + options: { outDir }, + }, + }, + }, + project: { configFilePath: `${this.rootDir}/tsconfig.json`, outDir }, + ...compilerOptions, + }); + this.addFiles(files); + this.compileAddons(this.compilerOptions.addons.getAddonsDir()); } /** @@ -46,11 +58,8 @@ export class CompilationEnv { return this.rootDir; } - public getCompiler(): Compiler { - return this.compiler; - } public getCompilerOptions(): CompilerOptions { - return this.compiler.getOptions(); + return this.compilerOptions; } public getSystem(): ts.System { @@ -141,6 +150,10 @@ export class CompilationEnv { return this; } + public getProjectDir(): string { + return this.buildDir; + } + /** * Installs project source code from provided `source` parameter into the * build directory, i.e. `this.buildDir`. @@ -173,7 +186,7 @@ export class CompilationEnv { } public addProjectFile(relativePath: string, content: string): this { - this.system.writeFile(resolveProjectPath(this.system, this.buildDir, relativePath), content); + this.addFile(resolveProjectPath(this.system, this.buildDir, relativePath), content); return this; } @@ -183,14 +196,48 @@ export class CompilationEnv { public getProjectFile(filePath: string): ProjectFile | undefined { const file = this.system.readDirectory(this.rootDir).find(it => it.endsWith(filePath)); - if (file) { - return projectFile(this.system, this.buildDir, file); - } - return undefined; + return file ? projectFile(this.system, this.buildDir, file) : undefined; } - public compile(): ts.EmitResult { - return this.compiler.compile(); + public compile(): this & CompilationResult { + const result = new Compiler(this.compilerOptions, this.system).compile(); + // @ts-expect-error - method is not part of the original object + this.getDiagnostics = () => result.diagnostics; + // @ts-expect-error - method is not part of the original object + this.hasEmitSkipped = () => result.emitSkipped; + // @ts-expect-error - method is not part of the original object + this.getEmittedFiles = () => result.emittedFiles ?? []; + // @ts-expect-error - method is not part of the original object + this.hasFailures = () => result.diagnostics.some(it => it.category === ts.DiagnosticCategory.Error); + // @ts-expect-error - method is not part of the original object + this.getFailureReport = (filter?: string) => { + const report = ts.formatDiagnostics(result.diagnostics, { + getCanonicalFileName: (path: string) => path, + getCurrentDirectory: () => this.system.getCurrentDirectory(), + getNewLine: () => this.system.newLine, + }); + return filter + ? report + .split("\n") + .filter(it => it.includes(filter)) + .join("\n") + : report; + }; + // @ts-expect-error - New methods were added to the object + return this; + } + + public getCompiledDir(): string { + return resolveProjectPath(this.system, this.rootDir, this.getCompilerOptions().project.outDir ?? DEFAULT_OUT_DIR); + } + + public getCompiledFiles(): ProjectFile[] { + return this.system.readDirectory(this.getCompiledDir()).map(it => projectFile(this.getSystem(), this.buildDir, it)); + } + + public getCompiledFile(filePath: string): ProjectFile | undefined { + const file = this.system.readDirectory(this.getCompiledDir()).find(it => it.endsWith(filePath)); + return file ? projectFile(this.system, this.buildDir, file) : undefined; } private compileAddons(addonsDir: string) { @@ -232,15 +279,28 @@ export class CompilationEnv { return; } Object.keys(files).forEach(file => { - this.system.writeFile(file, files[file]); + this.addFile(resolveProjectPath(this.system, this.buildDir, file), files[file]); }); } + private addFile(filePath: string, content: string): void { + this.system.writeFile(filePath, content); + this.compilerOptions.tsconfig.fileNames.push(filePath); + } + private getAddonRegistry(): AddonRegistry { - return this.compiler.getOptions().addons; + return this.compilerOptions.addons; } } +export type CompilationResult = { + hasEmitSkipped: () => boolean; + getEmittedFiles: () => string[]; + hasFailures: () => boolean; + getFailureReport: (filter?: string) => string; + getDiagnostics: () => ts.Diagnostic[]; +}; + export type CompilationOptions = { compilerOptions?: Partial; files?: Record; diff --git a/packages/testing/src/compile-options.spec.ts b/packages/testing/src/compile-options.spec.ts new file mode 100644 index 00000000..0e0c8e5e --- /dev/null +++ b/packages/testing/src/compile-options.spec.ts @@ -0,0 +1,32 @@ +import { createBrowserSystem } from "@quatico/websmith-core"; +import ts from "typescript"; +import { compileOptions } from "./compile-options"; + +describe("compileOptions", () => { + it("should return correct defaults", () => { + const actual = compileOptions(createBrowserSystem()); + + expect(actual).toEqual({ + addons: expect.any(Object), + buildDir: "/src", + reporter: expect.any(Object), + debug: false, + sourceMap: false, + transpileOnly: false, + watch: false, + project: { + module: ts.ModuleKind.ESNext, + target: ts.ScriptTarget.Latest, + configFilePath: "./tsconfig.json", + }, + targets: [], + tsconfig: { + options: { + outDir: "./dist", + }, + fileNames: [], + errors: [], + }, + }); + }); +}); diff --git a/packages/testing/src/compile-options.ts b/packages/testing/src/compile-options.ts index f3d69eda..458ee3a0 100644 --- a/packages/testing/src/compile-options.ts +++ b/packages/testing/src/compile-options.ts @@ -10,6 +10,7 @@ import { ReporterMock } from "./ReporterMock"; import { resolvePath } from "./compilation/resolve-path"; const DEFAULT_BUILD_DIR = "./src"; +const DEFAULT_OUT_DIR = "./dist"; const DEFAULT_ADDONS_DIR = "../addons"; export const compileOptions = ( @@ -29,8 +30,18 @@ export const compileOptions = ( transpileOnly: false, watch: false, ...overrides, - project: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.Latest, configFilePath: "./tsconfig.json", ...overrides?.project }, + project: { + module: ts.ModuleKind.ESNext, + target: ts.ScriptTarget.Latest, + configFilePath: `./tsconfig.json`, + ...overrides?.project, + }, targets: overrides?.targets ?? [], - tsconfig: { options: {}, fileNames: system.readDirectory(buildDir), errors: [], ...overrides?.tsconfig }, + tsconfig: { + options: { outDir: overrides?.project?.outDir ?? DEFAULT_OUT_DIR }, + fileNames: system.readDirectory(buildDir), + errors: [], + ...overrides?.tsconfig, + }, }; }; From eddf083c4ae57d525483354b9752722977708ad6 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 15:23:34 +0200 Subject: [PATCH 14/52] B Fixes two issues with the compiler + Not all emitted files are added to ts.EmitResult + tsLibDefaults cannot be added to file system, when browserSystem is used --- packages/core/src/compiler/Compiler.spec.ts | 15 +++++++++++++++ packages/core/src/compiler/Compiler.ts | 4 ++-- packages/core/src/environment/browser-system.ts | 13 ++++++++----- packages/core/test/compile-options.ts | 14 ++++++++++++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/core/src/compiler/Compiler.spec.ts b/packages/core/src/compiler/Compiler.spec.ts index 5c80f59a..8463a6b8 100644 --- a/packages/core/src/compiler/Compiler.spec.ts +++ b/packages/core/src/compiler/Compiler.spec.ts @@ -152,6 +152,21 @@ describe("compile", () => { expect(testObj.getContext("*")?.getConfig().options).toEqual(expect.objectContaining({ outDir: "./lib/expected" })); }); + + it("yields output w/ with defaults", () => { + const { fileSystem } = compileSystem({ + "src/target.ts": ` + export const computeDate = async (): Promise => new Date(); + `, + }); + + new CompilerTestClass(compileOptions(fileSystem), fileSystem).compile(); + + expect(fileSystem.readFile("/src/target.js")).toMatchInlineSnapshot(` + "export const computeDate = async () => new Date(); + " + `); + }); }); describe("emitSourceFile", () => { diff --git a/packages/core/src/compiler/Compiler.ts b/packages/core/src/compiler/Compiler.ts index 1dc9736d..fed69064 100644 --- a/packages/core/src/compiler/Compiler.ts +++ b/packages/core/src/compiler/Compiler.ts @@ -103,10 +103,10 @@ export class Compiler { for (const fileName of this.getRootFiles()) { const fragment = this.emitSourceFile(fileName, target, writeFile); if (fragment?.files.length > 0) { - result.emittedFiles = fragment.files.map(cur => cur.name); + result.emittedFiles?.push(...fragment.files.map(cur => cur.name)); } else { fragment.diagnostics?.forEach(diagnostic => this.reporter.reportDiagnostic(diagnostic)); - result.diagnostics = fragment.diagnostics ?? []; + result.diagnostics = [...result.diagnostics, ...(fragment.diagnostics ?? [])]; result.emitSkipped = !!fragment.diagnostics && fragment.diagnostics.length > 0 ? true : false; } } diff --git a/packages/core/src/environment/browser-system.ts b/packages/core/src/environment/browser-system.ts index 18ae4877..f8540384 100644 --- a/packages/core/src/environment/browser-system.ts +++ b/packages/core/src/environment/browser-system.ts @@ -57,11 +57,14 @@ class PathWatcherRegistry { } } -export const createBrowserSystem = (files?: Record, useCaseSensitiveFileNames = false): ts.System => { - const knownFiles = Object.entries({ ...(files ?? tsLibDefaults) }).reduce((acc: Record, [name, content]) => { - acc[resolvePath(name)] = content; - return acc; - }, {}); +export const createBrowserSystem = (files?: Record, useCaseSensitiveFileNames = false, addLibDefaults = false): ts.System => { + const knownFiles = Object.entries({ ...(files ?? {}), ...(addLibDefaults ? tsLibDefaults : {}) }).reduce( + (acc: Record, [name, content]) => { + acc[resolvePath(name)] = content; + return acc; + }, + {} + ); const pathWatchers = new PathWatcherRegistry(); diff --git a/packages/core/test/compile-options.ts b/packages/core/test/compile-options.ts index 21058492..a468bee5 100644 --- a/packages/core/test/compile-options.ts +++ b/packages/core/test/compile-options.ts @@ -22,8 +22,18 @@ export const compileOptions = ( transpileOnly: false, watch: false, ...overrides, - project: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.Latest, configFilePath: "./tsconfig.json", ...overrides?.project }, + project: { + module: ts.ModuleKind.ESNext, + target: ts.ScriptTarget.Latest, + configFilePath: "./tsconfig.json", + ...overrides?.project, + }, targets: overrides?.targets ?? [], - tsconfig: { options: {}, fileNames: system.readDirectory("./src"), errors: [], ...overrides?.tsconfig }, + tsconfig: { + options: {}, + fileNames: system.readDirectory("./src"), + errors: [], + ...overrides?.tsconfig, + }, }; }; From dc7b8b0a80be2d222a911797564d375822f5f562 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 15:25:19 +0200 Subject: [PATCH 15/52] B Fixes hoisting issue with linked workspace packages --- .npmrc | 3 ++- packages/test/src/test-examples/bar-addon.test.ts | 2 -- packages/testing/src/compilation/environment.spec.ts | 4 ---- packages/testing/src/compilation/environment.ts | 1 - packages/testing/src/compile-options.ts | 1 - 5 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.npmrc b/.npmrc index 0453efcd..0123f98e 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ -registry=https://registry.npmjs.org \ No newline at end of file +registry=https://registry.npmjs.org +node-linker=hoisted diff --git a/packages/test/src/test-examples/bar-addon.test.ts b/packages/test/src/test-examples/bar-addon.test.ts index 4ae4e691..4676462f 100644 --- a/packages/test/src/test-examples/bar-addon.test.ts +++ b/packages/test/src/test-examples/bar-addon.test.ts @@ -1,6 +1,4 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { compilationEnv } from "@quatico/websmith-testing"; describe("test-project-foo", () => { diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index 4367a8b2..f934fae5 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -1,7 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { resolve } from "path"; import ts from "typescript"; import { compilationEnv } from "./environment"; diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index c1192b3a..751966a7 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -87,7 +87,6 @@ export class CompilationEnv { return this.getAddonRegistry().getAddonsDir(); } - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents public getActiveAddon(addonName: string): CompilerAddon | undefined { return this.getAddonRegistry() .getAvailableAddons() diff --git a/packages/testing/src/compile-options.ts b/packages/testing/src/compile-options.ts index 458ee3a0..6f07c863 100644 --- a/packages/testing/src/compile-options.ts +++ b/packages/testing/src/compile-options.ts @@ -15,7 +15,6 @@ const DEFAULT_ADDONS_DIR = "../addons"; export const compileOptions = ( system: ts.System, - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents overrides?: Partial & { tsconfig?: Partial; project?: Partial; targets?: string[] } ): CompilerOptions => { const reporter = new ReporterMock(system); From 795752cb2b5bfe63f75ea84b7a90b860ebd3d067 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 15:30:52 +0200 Subject: [PATCH 16/52] a Fixes build and linting issues --- packages/test/src/test-examples/bar-addon.test.ts | 2 +- packages/testing/src/compilation/environment.ts | 1 + packages/testing/src/compile-options.ts | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/test/src/test-examples/bar-addon.test.ts b/packages/test/src/test-examples/bar-addon.test.ts index 4676462f..f1a533d4 100644 --- a/packages/test/src/test-examples/bar-addon.test.ts +++ b/packages/test/src/test-examples/bar-addon.test.ts @@ -43,7 +43,7 @@ describe("test-project-foo", () => { const actual = testObj.compile(); - expect(actual.emittedFiles![0]).toMatchInlineSnapshot(` + expect(actual.getCompiledFile("foo.js")).toMatchInlineSnapshot(` "export const foo = () => { console.log("foo"); }; diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 751966a7..c1192b3a 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -87,6 +87,7 @@ export class CompilationEnv { return this.getAddonRegistry().getAddonsDir(); } + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents public getActiveAddon(addonName: string): CompilerAddon | undefined { return this.getAddonRegistry() .getAvailableAddons() diff --git a/packages/testing/src/compile-options.ts b/packages/testing/src/compile-options.ts index 6f07c863..458ee3a0 100644 --- a/packages/testing/src/compile-options.ts +++ b/packages/testing/src/compile-options.ts @@ -15,6 +15,7 @@ const DEFAULT_ADDONS_DIR = "../addons"; export const compileOptions = ( system: ts.System, + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents overrides?: Partial & { tsconfig?: Partial; project?: Partial; targets?: string[] } ): CompilerOptions => { const reporter = new ReporterMock(system); From 81d8c3f0fe3715b50b3564286da4f1a3b7cba326 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 16:32:06 +0200 Subject: [PATCH 17/52] F Enable to copy addon and project files from actual FS into virtual compilation environment --- .../test/src/test-examples/bar-addon.test.ts | 26 +++++++--- .../testing/src/compilation/copy-directory.ts | 47 +++++++++++++------ .../testing/src/compilation/environment.ts | 30 ++++++++---- 3 files changed, 73 insertions(+), 30 deletions(-) diff --git a/packages/test/src/test-examples/bar-addon.test.ts b/packages/test/src/test-examples/bar-addon.test.ts index f1a533d4..a39e647e 100644 --- a/packages/test/src/test-examples/bar-addon.test.ts +++ b/packages/test/src/test-examples/bar-addon.test.ts @@ -1,9 +1,10 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { compilationEnv } from "@quatico/websmith-testing"; +import { join } from "path"; describe("test-project-foo", () => { it("should install addon successfully", () => { - const testObj = compilationEnv("__TEST__").addAddon("foo-addon", "../test-data/addons"); + const testObj = compilationEnv("__TEST__").addAddon("foo-addon", join(__dirname, "../test-data/addons")); const actual = testObj.getActiveAddons().map(it => it.name); @@ -22,13 +23,24 @@ describe("test-project-foo", () => { const actual = testObj.getProjectFile("foo.ts")!.getContent(); - expect(actual).toMatchInlineSnapshot( - ` + expect(actual).toMatchInlineSnapshot(` + " export const foo = () => { console.log("foo"); - }; - ` - ); + };p + " + `); + }); + + it("should compile source project from disk", () => { + const actual = compilationEnv("__TEST__").setupProjectFromDisk("test-project-foo", join(__dirname, "../test-data/projects")).compile(); + + expect(actual.getCompiledFile("foo.js")!.getContent()).toMatchInlineSnapshot(` + "export const foo = () => { + console.log("foo"); + }; + " + `); }); it("should compile source file content", () => { @@ -43,7 +55,7 @@ describe("test-project-foo", () => { const actual = testObj.compile(); - expect(actual.getCompiledFile("foo.js")).toMatchInlineSnapshot(` + expect(actual.getCompiledFile("foo.js")!.getContent()).toMatchInlineSnapshot(` "export const foo = () => { console.log("foo"); }; diff --git a/packages/testing/src/compilation/copy-directory.ts b/packages/testing/src/compilation/copy-directory.ts index 03fdb2a1..2163d420 100644 --- a/packages/testing/src/compilation/copy-directory.ts +++ b/packages/testing/src/compilation/copy-directory.ts @@ -1,32 +1,51 @@ import { join } from "path"; import ts from "typescript"; -export const copyDirectory = (system: ts.System, source: string, target: string, kind: "project" | "addon") => { +type SourcePath = { + system: ts.System; + path: string; + kind: "project" | "addon"; +}; + +type SourceFilePath = SourcePath & { + subDirName: string; +}; + +type TargetPath = { + system: ts.System; + path: string; +}; + +export const copyDirectory = (source: SourcePath, target: TargetPath) => { + const { system: srcSystem, path: srcPath, kind } = source; + // Throw an error if the source directory does not exist for addons - if (kind === "addon" && !system.directoryExists(source)) { - throw new Error(`Source directory ${source} does not exist.`); + if (kind === "addon" && !srcSystem.directoryExists(srcPath)) { + throw new Error(`Source directory ${srcPath} does not exist.`); } // Create target directory if it does not exist - if (!system.directoryExists(target)) { - system.createDirectory(target); + if (!target.system.directoryExists(target.path)) { + target.system.createDirectory(target.path); } - system.readDirectory(source).forEach(file => { - if (system.directoryExists(file)) { - copyDirectory(system, file, target, kind); + srcSystem.readDirectory(srcPath).forEach(file => { + if (srcSystem.directoryExists(file)) { + copyDirectory({ ...source, path: file }, target); } else { - const addonName = source.substring(source.lastIndexOf("/")); - copyFile(system, addonName, file, target, kind); + const subDirName = srcPath.substring(srcPath.lastIndexOf("/")); + copyFile({ ...source, subDirName, path: file }, target); } }); }; -const copyFile = (system: ts.System, subDirName: string, source: string, target: string, kind: "project" | "addon") => { - const fileContent = system.readFile(source); +const copyFile = (source: SourceFilePath, target: TargetPath) => { + const { system: srcSystem, path: srcPath, subDirName, kind } = source; + + const fileContent = srcSystem.readFile(srcPath); if (typeof fileContent === "string") { // Create a new file with the same path relative to `buildDir` - const targetPath = join(target, source.substring(source.indexOf(subDirName) + (kind === "project" ? subDirName.length + 1 : 0))); - system.writeFile(targetPath, fileContent); + const targetPath = join(target.path, srcPath.substring(srcPath.indexOf(subDirName) + (kind === "project" ? subDirName.length + 1 : 0))); + target.system.writeFile(targetPath, fileContent); } }; diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index c1192b3a..fc37a3bc 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -129,8 +129,9 @@ export class CompilationEnv { }, {}) ); } else { - const addonsSourceDir = resolvePath(this.system, this.rootDir, addonSource ?? DEFAULT_ADDONS_SOURCE_DIR, addonName); - copyDirectory(this.system, addonsSourceDir, addonTargetPath, "addon"); + const addonsSourceDir = resolveProjectPath(this.system, this.rootDir, join(addonSource ?? DEFAULT_ADDONS_SOURCE_DIR, addonName)); + const sourceFs = this.system.directoryExists(addonsSourceDir) ? this.system : ts.sys; + copyDirectory({ system: sourceFs, path: addonsSourceDir, kind: "addon" }, { system: this.system, path: addonTargetPath }); } this.compileAddons(this.getAddonRegistry().getAddonsDir()); @@ -140,9 +141,10 @@ export class CompilationEnv { public addAddons(addonNames: string[], addonsSourceDir?: string): this { const addonsDir = this.getAddonsDir(); - const addonsSourceDirPath = resolvePath(this.system, this.rootDir, addonsSourceDir ?? DEFAULT_ADDONS_SOURCE_DIR); + const addonsSourceDirPath = resolveProjectPath(this.system, this.rootDir, addonsSourceDir ?? DEFAULT_ADDONS_SOURCE_DIR); + const sourceFs = this.system.directoryExists(addonsSourceDirPath) ? this.system : ts.sys; addonNames.forEach(addon => { - copyDirectory(this.system, join(addonsSourceDirPath, addon), addonsDir, "addon"); + copyDirectory({ system: sourceFs, path: join(addonsSourceDirPath, addon), kind: "addon" }, { system: this.system, path: addonsDir }); }); this.compileAddons(addonsDir); this.getAddonRegistry().refresh(); @@ -180,8 +182,14 @@ export class CompilationEnv { * @returns this instance */ public setupProjectFromDisk(projectName: string, projectsSourceDir?: string): this { - const projectsSourcePath = resolvePath(this.system, this.rootDir, projectsSourceDir ?? DEFAULT_PROJECTS_SOURCE_DIR); - copyDirectory(this.system, join(projectsSourcePath, projectName), this.rootDir, "project"); + const projectsSourcePath = resolveProjectPath(this.system, this.rootDir, projectsSourceDir ?? DEFAULT_PROJECTS_SOURCE_DIR); + const sourceFs = this.system.directoryExists(projectsSourcePath) ? this.system : ts.sys; + copyDirectory( + { system: sourceFs, path: join(projectsSourcePath, projectName), kind: "project" }, + { system: this.system, path: this.rootDir } + ); + this.compilerOptions.tsconfig.fileNames = this.system.readDirectory(this.buildDir).filter(isSourceFile); + return this; } @@ -243,7 +251,7 @@ export class CompilationEnv { private compileAddons(addonsDir: string) { const addonsToCompile = this.system .readDirectory(addonsDir) - .filter(it => it.endsWith(".ts")) + .filter(isSourceFile) .map(it => dirname(it)); addonsToCompile.forEach(curDir => { @@ -253,7 +261,7 @@ export class CompilationEnv { buildDir: curDir, }), project: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES5 }, - tsconfig: { fileNames: this.system.readDirectory(curDir).filter(it => it.endsWith(".ts")), options: {}, errors: [] }, + tsconfig: { fileNames: this.system.readDirectory(curDir).filter(isSourceFile), options: {}, errors: [] }, }, this.system ).compile(); @@ -285,7 +293,9 @@ export class CompilationEnv { private addFile(filePath: string, content: string): void { this.system.writeFile(filePath, content); - this.compilerOptions.tsconfig.fileNames.push(filePath); + if (isSourceFile(filePath)) { + this.compilerOptions.tsconfig.fileNames.push(filePath); + } } private getAddonRegistry(): AddonRegistry { @@ -332,6 +342,8 @@ const resolveProjectPath = (system: ts.System, buildDir: string, relativePath: s return filePath; }; +const isSourceFile = (filePath: string): boolean => filePath.endsWith(".ts") || filePath.endsWith(".tsx"); + const isFiles = (source?: string | Record): source is Record => typeof source === "object"; export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => new CompilationEnv(rootDir, options); From ae5b8985f078dbecaffad7c59896ada8541b039e Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 16:41:23 +0200 Subject: [PATCH 18/52] t Removes cucumber tests from E2E testing environment Note: It'll be replaced with @quatico/webbloqs-testing --- jest.config.js | 3 +- jest.setup.ts | 10 - packages/test/package.json | 5 - .../src/{test-examples => }/bar-addon.test.ts | 10 +- packages/test/src/cucumber.test.ts | 11 - .../src/features/addon-configuration.feature | 61 ----- .../src/features/addon-contribution.feature | 71 ------ .../features/compiler-configuration.feature | 26 -- .../src/features/target-configuration.feature | 16 -- packages/test/src/steps/cli.steps.ts | 230 ------------------ packages/test/src/test-data-helper.ts | 13 - .../test-data/addons/bar-addon/addon.ts | 0 .../test-data/addons/foo-addon/addon.ts | 0 .../projects/test-project-foo/src/foo.ts | 0 .../projects/test-project-foo/tsconfig.json | 0 .../test-project-foobar/src/foobar.ts | 0 .../test-project-foobar/src/whatever.ts | 0 .../test-project-foobar/tsconfig.json | 0 .../projects/test-project-one/src/one.ts | 0 .../projects/test-project-one/src/three.ts | 0 .../projects/test-project-one/src/two.ts | 0 .../projects/test-project-one/tsconfig.json | 0 pnpm-lock.yaml | 158 ------------ 23 files changed, 6 insertions(+), 608 deletions(-) rename packages/test/src/{test-examples => }/bar-addon.test.ts (92%) delete mode 100644 packages/test/src/cucumber.test.ts delete mode 100644 packages/test/src/features/addon-configuration.feature delete mode 100644 packages/test/src/features/addon-contribution.feature delete mode 100644 packages/test/src/features/compiler-configuration.feature delete mode 100644 packages/test/src/features/target-configuration.feature delete mode 100644 packages/test/src/steps/cli.steps.ts delete mode 100644 packages/test/src/test-data-helper.ts rename packages/test/{src => }/test-data/addons/bar-addon/addon.ts (100%) rename packages/test/{src => }/test-data/addons/foo-addon/addon.ts (100%) rename packages/test/{src => }/test-data/projects/test-project-foo/src/foo.ts (100%) rename packages/test/{src => }/test-data/projects/test-project-foo/tsconfig.json (100%) rename packages/test/{src => }/test-data/projects/test-project-foobar/src/foobar.ts (100%) rename packages/test/{src => }/test-data/projects/test-project-foobar/src/whatever.ts (100%) rename packages/test/{src => }/test-data/projects/test-project-foobar/tsconfig.json (100%) rename packages/test/{src => }/test-data/projects/test-project-one/src/one.ts (100%) rename packages/test/{src => }/test-data/projects/test-project-one/src/three.ts (100%) rename packages/test/{src => }/test-data/projects/test-project-one/src/two.ts (100%) rename packages/test/{src => }/test-data/projects/test-project-one/tsconfig.json (100%) diff --git a/jest.config.js b/jest.config.js index 7117395e..9fb039d6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -17,7 +17,6 @@ module.exports = { "@quatico/websmith-webpack": "/packages/webpack/src", }, prettierPath: null, - modulePathIgnorePatterns: ["/packages/compiler/test/__mocks__/fs.ts"], setupFilesAfterEnv: ["/jest.setup.ts"], testRegex: "src/.*spec\\.(tsx?)$", testEnvironmentOptions: { url: "http://localhost/" }, @@ -35,5 +34,5 @@ module.exports = { }, transformIgnorePatterns: ["node_modules"], resetMocks: true, - watchman: false, + clearMocks: true, }; diff --git a/jest.setup.ts b/jest.setup.ts index 19a6b008..67f26459 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -1,14 +1,4 @@ /* eslint-disable no-console */ import { tsLibMocks } from "./packages/testing/src/tsLibMocks"; -import { readE2eTestData } from "./packages/test/src/test-data-helper"; tsLibMocks(); - -console.info = () => undefined; -console.log = () => undefined; - -afterEach(() => { - jest.clearAllMocks(); -}); - -export { readE2eTestData }; diff --git a/packages/test/package.json b/packages/test/package.json index 9550c9d7..1133c5f1 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -22,9 +22,7 @@ "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", - "@types/minimist": "^1.2.5", "@types/node": "^20.12.7", - "commander": "^12.0.0", "concurrently": "^8.2.2", "cross-env": "7.0.3", "eslint": "^9.1.1", @@ -36,9 +34,6 @@ "eslint-plugin-testing-library": "^6.2.2", "globals": "^15.0.0", "jest": "^29.7.0", - "jest-cucumber": "4.2.0", - "memfs": "^4.8.2", - "minimist": "^1.2.8", "path": "0.12.7", "prettier": "^3.2.5", "rimraf": "5.0.5", diff --git a/packages/test/src/test-examples/bar-addon.test.ts b/packages/test/src/bar-addon.test.ts similarity index 92% rename from packages/test/src/test-examples/bar-addon.test.ts rename to packages/test/src/bar-addon.test.ts index a39e647e..b763ff1c 100644 --- a/packages/test/src/test-examples/bar-addon.test.ts +++ b/packages/test/src/bar-addon.test.ts @@ -24,11 +24,11 @@ describe("test-project-foo", () => { const actual = testObj.getProjectFile("foo.ts")!.getContent(); expect(actual).toMatchInlineSnapshot(` - " - export const foo = () => { - console.log("foo"); - };p - " + " + export const foo = () => { + console.log("foo"); + };p + " `); }); diff --git a/packages/test/src/cucumber.test.ts b/packages/test/src/cucumber.test.ts deleted file mode 100644 index b3d9cb19..00000000 --- a/packages/test/src/cucumber.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * --------------------------------------------------------------------------------------------- - * Copyright (c) Quatico Solutions AG. All rights reserved. - * Licensed under the MIT License. See LICENSE in the project root for license information. - * --------------------------------------------------------------------------------------------- - */ -import { loadFeatures, autoBindSteps } from "jest-cucumber"; -import { cliSteps } from "./steps/cli.steps"; - -const features = loadFeatures("src/features/**/*.feature", { tagFilter: "not @skip" }); -autoBindSteps(features, [cliSteps]); diff --git a/packages/test/src/features/addon-configuration.feature b/packages/test/src/features/addon-configuration.feature deleted file mode 100644 index 07580e12..00000000 --- a/packages/test/src/features/addon-configuration.feature +++ /dev/null @@ -1,61 +0,0 @@ -Feature: Addon configuration - - Developers can provide compiler addons by placing ES modules with an "addon.ts" - in the addon folder, and configure via CLI arguments or config file options - which addons are applied during compilation. - - Scenario: Use CLI argument to activate a specific addon - # // ./addons/foo-addon/addon.ts - # export const activate = () => { - # console.log('foo-addon activated'); - # }; - # - # // ./addons/bar-addon/addon.ts - # export const activate = () => { - # console.log('bar-addon activated'); - # }; - Given Folder "./addons" contains addons "foo-addon, bar-addon" - - When User calls command "websmith --addons foo-addon" - - Then Addons "foo-addon" should be activated in compilation - - Scenario: Use CLI argument to activate multiple addons - # // ./addons/foo-addon/addon.ts - # export const activate = () => { - # console.log('foo-addon activated'); - # }; - # - # // ./addons/bar-addon/addon.ts - # export const activate = () => { - # console.log('bar-addon activated'); - # }; - Given Folder "./addons" contains addons "foo-addon, bar-addon" - - When User calls command "websmith --addons foo-addon, bar-addon" - - Then Addons "foo-addon, bar-addon" should be activated in compilation - - Scenario: Use a config file to select active addons - # // ./addons/foo-addon/addon.ts - # export const activate = () => { - # console.log('foo-addon activated'); - # }; - # - # // ./addons/bar-addon/addon.ts - # export const activate = () => { - # console.log('bar-addon activated'); - # }; - # - # // ./websmith.config.json - # { - # "addons": ["foo-addon"] - # } - Given A valid config file named "websmith.config.json" exists in project folder - And Config file "websmith.config.json" contains "addons" with "foo-addon" - And Folder "./addons" contains addons "foo-addon, bar-addon" - - When User calls command "websmith" - - Then Addons "foo-addon" should be activated in compilation - And Addons "bar-addon" should not be activated \ No newline at end of file diff --git a/packages/test/src/features/addon-contribution.feature b/packages/test/src/features/addon-contribution.feature deleted file mode 100644 index 0eabe5a4..00000000 --- a/packages/test/src/features/addon-contribution.feature +++ /dev/null @@ -1,71 +0,0 @@ -Feature: Feature: Addon contribution - - Developers can provide compiler addons by placing ES modules with an "addon.ts" - in the addons folder. Every addon needs to export an "activate" function that - receives a "AddonContext". Addons can register generator, pre-emit - transformer or emit transformer functions. - - Scenario: Run Compiler with all addons in default directory - Given Folder "./addons" contains addons "foo-addon, bar-addon" - - When User calls command "websmith" - - Then Addons "bar-addon, foo-addon" should be activated in compilation - - Scenario: Use CLI argument to select different addons directory - Given Folder "./my-addons" contains addons "foo-addon, bar-addon" - - When User calls command "websmith --addonsDir ./my-addons" - - Then Addons "bar-addon, foo-addon" should be activated in compilation - - Scenario: Provide generator addon to create additional input files - Given Folder "./addons" contains addon examples "example-generator" - And A test project "test-project-foo" is provided - - When User calls command "websmith" - - Then Addons "example-generator" should be activated in compilation - And A file "./dist/foo-added.js" exists containing string "const foo = ()" - - Scenario: Provide processor addon to modify 'foobar' module exports - Given Folder "./addons" contains addon examples "example-processor" - And A test project "test-project-foobar" is provided - And A file "./src/foobar.ts" exists containing string "function foobar(): string {" - - When User calls command "websmith" - - Then Addons "example-processor" should be activated in compilation - And A file content "./src/foobar.ts" exists containing string "export function foobar(): string {" - And A file "./dist/foobar.js" exists containing string "export function foobar() {" - And A file "./dist/foobar.d.ts" exists containing string "export declare function foobar(): string;" - And A file "./dist/whatever.js" exists containing string "function whatever()" - - Scenario: Provide transformer addon to rename 'foobar' functions to 'barfoo' - Given Folder "./addons" contains addon examples "example-transformer" - And A test project "test-project-foobar" is provided - And A file "./src/foobar.ts" exists containing string "function foobar(): string {" - - When User calls command "websmith" - - Then Addons "example-transformer" should be activated in compilation - And A file "./dist/foobar.js" exists containing string "function barfoo() {" - And A file "./dist/whatever.js" exists containing string "function whatever() {" - - Scenario: Provide result processor addon to add comment to generated files - Given Folder "./addons" contains addon examples "example-result-processor" - And A test project "test-project-one" is provided - - When User calls command "websmith" - - Then Addons "example-result-processor" should be activated in compilation - And A file "./dist/named-functions.json" exists containing names "one, two, three" - - Scenario: Provide a YAML generator addon to create additional documentation - Given Folder "./addons" contains addon examples "export-yaml-generator" - And A test project "test-project-one" is provided - - When User calls command "websmith" - - Then Addons "export-yaml-generator" should be activated in compilation - And A file "./dist/output.yaml" exists containing names "one, two, three" diff --git a/packages/test/src/features/compiler-configuration.feature b/packages/test/src/features/compiler-configuration.feature deleted file mode 100644 index b3a9a060..00000000 --- a/packages/test/src/features/compiler-configuration.feature +++ /dev/null @@ -1,26 +0,0 @@ -Feature: Compiler configuration - - Developers can provide a config (with default name "websmith.config.json") to - configure addons and targets to be used during compilation. - - Scenario: Use CLI argument to compile a project - Given A test project "test-project-one" is provided - - When User calls command "websmith" - - Then A file "./dist/one.js" exists containing string "const one = () =>" - And A file "./dist/two.js" exists containing string "const two = () =>" - And A file "./dist/three.js" exists containing string "const three = () =>" - - Scenario: Use CLI argument to select a custom configuration file - Given A test project "test-project-one" is provided - And A valid config file named "my-config.json" exists in project folder - And Config file "my-config.json" contains "addons" with "foo-addon" - And Folder "./addons" contains addons "foo-addon, bar-addon" - - When User calls command "websmith --config my-config.json" - - Then Addons "foo-addon" should be activated in compilation - And Addons "bar-addon" should not be activated -# TODO: And A file "./lib/one.js" exists containing string "const one = () =>" - diff --git a/packages/test/src/features/target-configuration.feature b/packages/test/src/features/target-configuration.feature deleted file mode 100644 index b26246f3..00000000 --- a/packages/test/src/features/target-configuration.feature +++ /dev/null @@ -1,16 +0,0 @@ -Feature: Target configuration - - Developers can configure different compilation targets using the - compiler config file, e.g., "websmith.config.json". For every named - target active addons and target specific options can be provided. - - Scenario: Provide custom configuration input to your addon - Given A valid config file named "websmith.config.json" exists in project folder - And Folder "./addons" contains addon examples "foobar-replace-transformer" - And Config file "websmith.config.json" contains target "foobar" - And Target project contains a module "target.ts" with a function is named "foobar" - - When User calls command "websmith --targets foobar" - - Then A file "./dist/target.js" exists containing string "barfoo" - And Every call to function "foobar" in "./src/target.ts" should be replaced with "barfoo" in "./dist/target.js" diff --git a/packages/test/src/steps/cli.steps.ts b/packages/test/src/steps/cli.steps.ts deleted file mode 100644 index eb34809a..00000000 --- a/packages/test/src/steps/cli.steps.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { createOptions } from "@quatico/websmith-compiler"; -import { CompilationContext, Compiler } from "@quatico/websmith-core"; -import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs"; -import { StepDefinitions } from "jest-cucumber"; -import parseArgs from "minimist"; -import { basename, dirname, isAbsolute, join, resolve } from "path"; - -const cleanWorkspace = true; - -export const cliSteps: StepDefinitions = ({ given, when, then }) => { - let compiler: Compiler; - let projectDir: string; - let rootDir: string; - let context: CompilationContext; - - beforeAll(() => { - projectDir = resolve("./test-source"); - rootDir = process.cwd(); - }); - - beforeEach(() => { - if (!existsSync(projectDir)) { - mkdirSync(projectDir); - } - if (!existsSync(join(projectDir, "src"))) { - mkdirSync(join(projectDir, "src")); - } - process.chdir(projectDir); - writeFileSync( - "./websmith.config.json", - JSON.stringify({ - addonsDir: "./addons", - }) - ); - writeFileSync( - "./tsconfig.json", - JSON.stringify({ - compilerOptions: { - target: "ESNEXT", - module: "ESNEXT", - lib: ["es2017", "es7", "es6", "dom"], - declaration: true, - outDir: "dist", - strict: true, - esModuleInterop: true, - }, - include: ["src"], - exclude: ["node_modules", "dist"], - }) - ); - }); - - afterEach(() => { - process.chdir(rootDir); - if (cleanWorkspace && existsSync(projectDir)) { - rmSync(projectDir, { recursive: true }); - } - }); - - given(/^A valid config file named "(.*)" exists in project folder$/, (configPath: string) => { - const resolvedConfigPath = resolvePath(configPath); - writeFileSync(resolvedConfigPath, JSON.stringify({ addonsDir: "./addons" })); - }); - - given(/^Config file "(.*)" contains "(.*)" with "(.*)"$/, (configPath: string, cfgProp: string, cfgValue: string) => { - const resolvedConfigPath = resolvePath(configPath); - const content = JSON.parse(readFileSync(resolvedConfigPath, "utf-8").toString()); - content[cfgProp] = stringToList(cfgValue); - writeFileSync(resolvedConfigPath, JSON.stringify(content)); - }); - - given(/^Config file "(.*)" contains target "(.*)"$/, (configPath: string, targetNames: string) => { - const resolvedConfigPath = resolvePath(configPath); - const content = JSON.parse(readFileSync(resolvedConfigPath, "utf-8").toString()); - const targets: string[] = stringToList(targetNames); - - content.targets = { ...(content.targets ?? {}), ...targets.map(it => ({ [it]: {} })) }; - writeFileSync(resolvedConfigPath, JSON.stringify(content)); - }); - - given(/^Folder "(.*)" contains addons "(.*)"$/, (addonsDir: string, addonNames: string) => { - const addonsDirPath = resolvePath(addonsDir); - stringToList(addonNames).forEach(addon => { - copyFolderRecursiveSync(join(__dirname, "../test-data/addons/", addon), addonsDirPath); - }); - }); - - given(/^Folder "(.*)" contains addon examples "(.*)"$/, (addonsDir: string, addonNames: string) => { - const addonsDirPath = resolvePath(addonsDir); - stringToList(addonNames).forEach(addon => { - copyFolderRecursiveSync(join(__dirname, "../../../examples/addons/", addon), addonsDirPath); - }); - }); - - given(/^Target project contains a module "(.*)" with a function is named "(.*)"$/, (moduleName: string, funcName: string) => { - const modulePath = resolvePath("src", moduleName); - writeFileSync(modulePath, `export const ${funcName} = () => { };`); - }); - - given(/^A test project "(.*)" is provided$/, (projectName: string) => { - copyFolderRecursiveSync(join(__dirname, "../test-data/projects/", projectName), projectDir, "files"); - }); - - when(/^User calls command "(.*)"$/, cliCommand => { - let command: string = cliCommand; - if (command === "websmith") { - command = ""; - } else if (command.startsWith("websmith ")) { - command = command.replace("websmith ", ""); - } - - const args = command - .replace(", ", ",") - .split(" ") - .map(it => it.trim()) - .filter(it => it.length > 0); - - compiler = new Compiler(createOptions({ ...parseArgs(args), buildDir: "./dist", project: "./tsconfig.json" })); - compiler.compile(); - context = compiler.getContext()!; - }); - - then(/^Addons "(.*)" should be activated in compilation$/, (addonNames: string) => { - const addons: string[] = stringToList(addonNames); - - expect( - compiler - .getOptions() - .addons.getAvailableAddons() - .map(cur => cur.name) - ).toEqual(addons); - }); - - then(/^Addons "(.*)" should not be activated$/, (addonNames: string) => { - const addons = stringToList(addonNames); - - addons.forEach(addon => { - expect( - compiler - .getOptions() - .addons.getAvailableAddons() - .map(cur => cur.name) - ).not.toContain(addon); - }); - }); - - then(/^A file "(.*)" exists containing string "(.*)"$/, (outFileName: string, funcName: string) => { - const outFilePath = resolvePath(`${outFileName}`); - expect(readFileSync(outFilePath, "utf-8").toString()).toContain(funcName); - }); - - then(/^A file content "(.*)" exists containing string "(.*)"$/, (outFileName: string, funcName: string) => { - const outFilePath = resolvePath(`${outFileName}`); - expect(context.getFileContent(outFilePath)).toContain(funcName); - }); - - then(/^A file "(.*)" exists containing names "(.*)"$/, (fileName: string, contents: string) => { - const filePath = resolvePath(fileName); - const expectedElements = stringToList(contents); - - const actualContent = readFileSync(filePath, "utf-8").toString(); - expectedElements.forEach(element => { - expect(actualContent).toContain(element); - }); - }); - - then( - /^Every call to function "(.*)" in "(.*)" should be replaced with "(.*)" in "(.*)"$/, - (oldFuncName: string, oldFileName: string, newFuncName: string, newFileName: string) => { - const oldContent = readFileSync(oldFileName, "utf-8").toString(); - const newContent = readFileSync(newFileName, "utf-8").toString(); - - expect(newContent.trim()).toBe(oldContent.replaceAll(oldFuncName, newFuncName).trim()); - } - ); -}; - -const copyFileSyncFn = (source: string, target: string) => { - let targetFile = target; - // If target is a directory, a new file with the same name will be created - if (existsSync(target)) { - if (lstatSync(target).isDirectory()) { - targetFile = join(target, basename(source)); - } - } - writeFileSync(targetFile, readFileSync(source)); -}; - -const copyFolderRecursiveSync = (source: string, target: string, kind: "folder" | "files" = "folder") => { - let files = []; - // Check if folder needs to be created or integrated - let targetFolder = join(target, basename(source)); - if (kind === "files") { - targetFolder = join(dirname(target), "test-source"); - } - if (!existsSync(targetFolder)) { - mkdirSync(targetFolder, { recursive: true }); - } - // Copy - if (lstatSync(source).isDirectory()) { - files = readdirSync(source); - files.forEach(file => { - const curSource = join(source, file); - if (lstatSync(curSource).isDirectory()) { - copyFolderRecursiveSync(curSource, targetFolder); - } else { - copyFileSyncFn(curSource, targetFolder); - } - }); - } -}; - -const resolvePath = (...configPath: string[]) => { - let resolvedPath = join(...configPath); - if (!isAbsolute(resolvedPath)) { - resolvedPath = join(process.cwd(), ...configPath); - } - return resolvedPath; -}; - -const stringToList = (stringValue: string): string[] => { - let result: string[] = [stringValue]; - if (stringValue.indexOf(",") > -1) { - result = stringValue - .split(",") - .map(cur => cur.trim()) - .filter(cur => cur.length > 0); - } - return result; -}; diff --git a/packages/test/src/test-data-helper.ts b/packages/test/src/test-data-helper.ts deleted file mode 100644 index ff78e2a0..00000000 --- a/packages/test/src/test-data-helper.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * --------------------------------------------------------------------------------------------- - * Copyright (c) Quatico Solutions AG. All rights reserved. - * Licensed under the MIT License. See LICENSE in the project root for license information. - * --------------------------------------------------------------------------------------------- - */ -import path from "path"; - -const fs = jest.requireActual("fs"); - -export const readE2eTestData = ({ name, dataType = "json" }: { name: string; dataType: string }): string => { - return fs.readFileSync(path.resolve(__dirname, "__data__", dataType, `${name}.${dataType}`)).toString(); -}; diff --git a/packages/test/src/test-data/addons/bar-addon/addon.ts b/packages/test/test-data/addons/bar-addon/addon.ts similarity index 100% rename from packages/test/src/test-data/addons/bar-addon/addon.ts rename to packages/test/test-data/addons/bar-addon/addon.ts diff --git a/packages/test/src/test-data/addons/foo-addon/addon.ts b/packages/test/test-data/addons/foo-addon/addon.ts similarity index 100% rename from packages/test/src/test-data/addons/foo-addon/addon.ts rename to packages/test/test-data/addons/foo-addon/addon.ts diff --git a/packages/test/src/test-data/projects/test-project-foo/src/foo.ts b/packages/test/test-data/projects/test-project-foo/src/foo.ts similarity index 100% rename from packages/test/src/test-data/projects/test-project-foo/src/foo.ts rename to packages/test/test-data/projects/test-project-foo/src/foo.ts diff --git a/packages/test/src/test-data/projects/test-project-foo/tsconfig.json b/packages/test/test-data/projects/test-project-foo/tsconfig.json similarity index 100% rename from packages/test/src/test-data/projects/test-project-foo/tsconfig.json rename to packages/test/test-data/projects/test-project-foo/tsconfig.json diff --git a/packages/test/src/test-data/projects/test-project-foobar/src/foobar.ts b/packages/test/test-data/projects/test-project-foobar/src/foobar.ts similarity index 100% rename from packages/test/src/test-data/projects/test-project-foobar/src/foobar.ts rename to packages/test/test-data/projects/test-project-foobar/src/foobar.ts diff --git a/packages/test/src/test-data/projects/test-project-foobar/src/whatever.ts b/packages/test/test-data/projects/test-project-foobar/src/whatever.ts similarity index 100% rename from packages/test/src/test-data/projects/test-project-foobar/src/whatever.ts rename to packages/test/test-data/projects/test-project-foobar/src/whatever.ts diff --git a/packages/test/src/test-data/projects/test-project-foobar/tsconfig.json b/packages/test/test-data/projects/test-project-foobar/tsconfig.json similarity index 100% rename from packages/test/src/test-data/projects/test-project-foobar/tsconfig.json rename to packages/test/test-data/projects/test-project-foobar/tsconfig.json diff --git a/packages/test/src/test-data/projects/test-project-one/src/one.ts b/packages/test/test-data/projects/test-project-one/src/one.ts similarity index 100% rename from packages/test/src/test-data/projects/test-project-one/src/one.ts rename to packages/test/test-data/projects/test-project-one/src/one.ts diff --git a/packages/test/src/test-data/projects/test-project-one/src/three.ts b/packages/test/test-data/projects/test-project-one/src/three.ts similarity index 100% rename from packages/test/src/test-data/projects/test-project-one/src/three.ts rename to packages/test/test-data/projects/test-project-one/src/three.ts diff --git a/packages/test/src/test-data/projects/test-project-one/src/two.ts b/packages/test/test-data/projects/test-project-one/src/two.ts similarity index 100% rename from packages/test/src/test-data/projects/test-project-one/src/two.ts rename to packages/test/test-data/projects/test-project-one/src/two.ts diff --git a/packages/test/src/test-data/projects/test-project-one/tsconfig.json b/packages/test/test-data/projects/test-project-one/tsconfig.json similarity index 100% rename from packages/test/src/test-data/projects/test-project-one/tsconfig.json rename to packages/test/test-data/projects/test-project-one/tsconfig.json diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3d1a5bef..86006e4a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -454,15 +454,9 @@ importers: '@types/jest': specifier: ^29.5.12 version: 29.5.12 - '@types/minimist': - specifier: ^1.2.5 - version: 1.2.5 '@types/node': specifier: ^20.12.7 version: 20.12.7 - commander: - specifier: ^12.0.0 - version: 12.0.0 concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -496,15 +490,6 @@ importers: jest: specifier: ^29.7.0 version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) - jest-cucumber: - specifier: 4.2.0 - version: 4.2.0(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5))) - memfs: - specifier: ^4.8.2 - version: 4.8.2 - minimist: - specifier: ^1.2.8 - version: 1.2.8 path: specifier: 0.12.7 version: 0.12.7 @@ -1433,16 +1418,9 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@cucumber/gherkin@17.0.2': - resolution: {integrity: sha512-U8ZxbYVLEXqUy4Fx9BJ5ncIzXz/eVg+fKV2F8B1t5f6eDMgPQ2Aq3M8gy3yE422OAuJ+RFRuezNtuEbpmf2r4g==} - hasBin: true - '@cucumber/gherkin@28.0.0': resolution: {integrity: sha512-Ee6zJQq0OmIUPdW0mSnsCsrWA2PZAELNDPICD2pLfs0Oz7RAPgj80UsD2UCtqyAhw2qAR62aqlktKUlai5zl/A==} - '@cucumber/messages@14.1.2': - resolution: {integrity: sha512-QV8sA7QwHuDGwTrFOCu2xMUvW9bLkBmMMRKId7s4swpQj9WyL8uFMsQ452W6wWTKNdIfKhRU3Ykptr87SKfg7w==} - '@cucumber/messages@24.1.0': resolution: {integrity: sha512-hxVHiBurORcobhVk80I9+JkaKaNXkW6YwGOEFIh/2aO+apAN+5XJgUUWjng9NwqaQrW1sCFuawLB1AuzmBaNdQ==} @@ -1718,36 +1696,6 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@protobufjs/aspromise@1.1.2': - resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} - - '@protobufjs/base64@1.1.2': - resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} - - '@protobufjs/codegen@2.0.4': - resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} - - '@protobufjs/eventemitter@1.1.0': - resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} - - '@protobufjs/fetch@1.1.0': - resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} - - '@protobufjs/float@1.0.2': - resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} - - '@protobufjs/inquire@1.1.0': - resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} - - '@protobufjs/path@1.1.2': - resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} - - '@protobufjs/pool@1.1.0': - resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} - - '@protobufjs/utf8@1.1.0': - resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -1901,9 +1849,6 @@ packages: '@types/lodash@4.17.0': resolution: {integrity: sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==} - '@types/long@4.0.2': - resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} - '@types/minimatch@5.1.2': resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} @@ -1934,9 +1879,6 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - '@types/uuid@8.3.4': - resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} - '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} @@ -2514,10 +2456,6 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -3415,20 +3353,6 @@ packages: ts-node: optional: true - jest-cucumber@4.2.0: - resolution: {integrity: sha512-2xvHaxZ09fdPwCA50N/qjicmt44R87K2flhSdPN1EsHNzHpaeblby93q/YgcAl9IN9GBpqZIH3C77n90sDMBgA==} - peerDependencies: - '@types/jest': '>=29.5.12' - jest: '>=29.7.0' - vitest: '>=1.4.0' - peerDependenciesMeta: - '@types/jest': - optional: true - jest: - optional: true - vitest: - optional: true - jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3660,9 +3584,6 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} - long@4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -3965,10 +3886,6 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} - protobufjs@6.11.4: - resolution: {integrity: sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==} - hasBin: true - proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -4492,10 +4409,6 @@ packages: util@0.10.4: resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true @@ -5412,22 +5325,10 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@cucumber/gherkin@17.0.2': - dependencies: - '@cucumber/messages': 14.1.2 - commander: 7.2.0 - source-map-support: 0.5.21 - '@cucumber/gherkin@28.0.0': dependencies: '@cucumber/messages': 24.1.0 - '@cucumber/messages@14.1.2': - dependencies: - '@types/uuid': 8.3.4 - protobufjs: 6.11.4 - uuid: 8.3.2 - '@cucumber/messages@24.1.0': dependencies: '@types/uuid': 9.0.8 @@ -5897,29 +5798,6 @@ snapshots: '@pkgr/core@0.1.1': {} - '@protobufjs/aspromise@1.1.2': {} - - '@protobufjs/base64@1.1.2': {} - - '@protobufjs/codegen@2.0.4': {} - - '@protobufjs/eventemitter@1.1.0': {} - - '@protobufjs/fetch@1.1.0': - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/inquire': 1.1.0 - - '@protobufjs/float@1.0.2': {} - - '@protobufjs/inquire@1.1.0': {} - - '@protobufjs/path@1.1.2': {} - - '@protobufjs/pool@1.1.0': {} - - '@protobufjs/utf8@1.1.0': {} - '@sinclair/typebox@0.27.8': {} '@sinonjs/commons@3.0.1': @@ -6065,8 +5943,6 @@ snapshots: '@types/lodash@4.17.0': {} - '@types/long@4.0.2': {} - '@types/minimatch@5.1.2': {} '@types/minimist@1.2.5': {} @@ -6094,8 +5970,6 @@ snapshots: '@types/stack-utils@2.0.3': {} - '@types/uuid@8.3.4': {} - '@types/uuid@9.0.8': {} '@types/webpack@5.28.5(@swc/core@1.5.0)(webpack-cli@5.1.4(webpack@5.91.0))': @@ -6810,8 +6684,6 @@ snapshots: commander@2.20.3: {} - commander@7.2.0: {} - concat-map@0.0.1: {} concurrently@8.2.2: @@ -7858,16 +7730,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-cucumber@4.2.0(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5))): - dependencies: - '@cucumber/gherkin': 17.0.2 - callsites: 3.1.0 - glob: 10.3.12 - uuid: 9.0.1 - optionalDependencies: - '@types/jest': 29.5.12 - jest: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) - jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -8212,8 +8074,6 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 - long@4.0.0: {} - loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -8551,22 +8411,6 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 - protobufjs@6.11.4: - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/base64': 1.1.2 - '@protobufjs/codegen': 2.0.4 - '@protobufjs/eventemitter': 1.1.0 - '@protobufjs/fetch': 1.1.0 - '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.0 - '@protobufjs/path': 1.1.2 - '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.0 - '@types/long': 4.0.2 - '@types/node': 20.12.7 - long: 4.0.0 - proxy-from-env@1.1.0: {} punycode@2.3.1: {} @@ -9155,8 +8999,6 @@ snapshots: dependencies: inherits: 2.0.3 - uuid@8.3.2: {} - uuid@9.0.1: {} v8-compile-cache-lib@3.0.1: {} From ef937c651eeec9827a40ee3be97c4e8cd493a499 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 16:42:16 +0200 Subject: [PATCH 19/52] a Adds missing license headers --- packages/test/src/bar-addon.test.ts | 6 ++++++ packages/testing/README.md | 6 ++++++ packages/testing/src/compilation/copy-directory.ts | 6 ++++++ packages/testing/src/compilation/environment.spec.ts | 6 ++++++ packages/testing/src/compilation/environment.ts | 6 ++++++ packages/testing/src/compilation/index.ts | 6 ++++++ packages/testing/src/compilation/resolve-path.ts | 6 ++++++ packages/testing/src/compile-options.spec.ts | 6 ++++++ 8 files changed, 48 insertions(+) diff --git a/packages/test/src/bar-addon.test.ts b/packages/test/src/bar-addon.test.ts index b763ff1c..153e2e9d 100644 --- a/packages/test/src/bar-addon.test.ts +++ b/packages/test/src/bar-addon.test.ts @@ -1,3 +1,9 @@ +/* + * --------------------------------------------------------------------------------------------- + * Copyright (c) Quatico Solutions AG. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + * --------------------------------------------------------------------------------------------- + */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { compilationEnv } from "@quatico/websmith-testing"; import { join } from "path"; diff --git a/packages/testing/README.md b/packages/testing/README.md index dfb4bfb1..6408530c 100644 --- a/packages/testing/README.md +++ b/packages/testing/README.md @@ -1,3 +1,9 @@ + # Websmith Testing API This library provides a simple API for testing Websmith addons in your project. diff --git a/packages/testing/src/compilation/copy-directory.ts b/packages/testing/src/compilation/copy-directory.ts index 2163d420..6a79aff9 100644 --- a/packages/testing/src/compilation/copy-directory.ts +++ b/packages/testing/src/compilation/copy-directory.ts @@ -1,3 +1,9 @@ +/* + * --------------------------------------------------------------------------------------------- + * Copyright (c) Quatico Solutions AG. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + * --------------------------------------------------------------------------------------------- + */ import { join } from "path"; import ts from "typescript"; diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index f934fae5..e6baa323 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -1,3 +1,9 @@ +/* + * --------------------------------------------------------------------------------------------- + * Copyright (c) Quatico Solutions AG. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + * --------------------------------------------------------------------------------------------- + */ import { resolve } from "path"; import ts from "typescript"; import { compilationEnv } from "./environment"; diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index fc37a3bc..1955c2da 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -1,3 +1,9 @@ +/* + * --------------------------------------------------------------------------------------------- + * Copyright (c) Quatico Solutions AG. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + * --------------------------------------------------------------------------------------------- + */ import { AddonRegistry, Compiler, createBrowserSystem, type CompilerAddon, type CompilerOptions } from "@quatico/websmith-core"; import { basename, dirname, extname, isAbsolute, join } from "path"; import requireFromString from "require-from-string"; diff --git a/packages/testing/src/compilation/index.ts b/packages/testing/src/compilation/index.ts index b9e1dabb..67bf11e4 100644 --- a/packages/testing/src/compilation/index.ts +++ b/packages/testing/src/compilation/index.ts @@ -1 +1,7 @@ +/* + * --------------------------------------------------------------------------------------------- + * Copyright (c) Quatico Solutions AG. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + * --------------------------------------------------------------------------------------------- + */ export { compilationEnv, type CompilationOptions, type CompilationEnv } from "./environment"; diff --git a/packages/testing/src/compilation/resolve-path.ts b/packages/testing/src/compilation/resolve-path.ts index 097bb210..21d24962 100644 --- a/packages/testing/src/compilation/resolve-path.ts +++ b/packages/testing/src/compilation/resolve-path.ts @@ -1,3 +1,9 @@ +/* + * --------------------------------------------------------------------------------------------- + * Copyright (c) Quatico Solutions AG. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + * --------------------------------------------------------------------------------------------- + */ import { isAbsolute, join } from "path"; import ts from "typescript"; diff --git a/packages/testing/src/compile-options.spec.ts b/packages/testing/src/compile-options.spec.ts index 0e0c8e5e..41581031 100644 --- a/packages/testing/src/compile-options.spec.ts +++ b/packages/testing/src/compile-options.spec.ts @@ -1,3 +1,9 @@ +/* + * --------------------------------------------------------------------------------------------- + * Copyright (c) Quatico Solutions AG. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + * --------------------------------------------------------------------------------------------- + */ import { createBrowserSystem } from "@quatico/websmith-core"; import ts from "typescript"; import { compileOptions } from "./compile-options"; From a869eb8abcc4db8632866c9ea5a6d13c9e40bf63 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 16:50:06 +0200 Subject: [PATCH 20/52] r Renames CompilationAddon API to prefer `getName()` instead of `name` accessor --- packages/compiler/src/command.spec.ts | 6 +++--- packages/compiler/src/options.spec.ts | 4 ++-- packages/core/src/compiler/addons/AddonRegistry.spec.ts | 6 +++--- packages/core/src/compiler/addons/AddonRegistry.ts | 2 +- packages/core/src/compiler/addons/CompilerAddon.ts | 2 +- packages/core/src/compiler/addons/addon-resolver.spec.ts | 4 ++-- packages/core/src/compiler/addons/addon-resolver.ts | 2 +- packages/test/src/bar-addon.test.ts | 2 +- packages/testing/src/compilation/environment.spec.ts | 8 ++++---- packages/testing/src/compilation/environment.ts | 2 +- packages/webpack/src/options.spec.ts | 4 ++-- 11 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/compiler/src/command.spec.ts b/packages/compiler/src/command.spec.ts index 01895d3d..ad279a3c 100644 --- a/packages/compiler/src/command.spec.ts +++ b/packages/compiler/src/command.spec.ts @@ -219,7 +219,7 @@ describe("addCompileCommand#addons", () => { target .getOptions() .addons.getAvailableAddons() - .map((it: CompilerAddon) => it.name) + .map((it: CompilerAddon) => it.getName()) ).toEqual(["expected"]); }); @@ -258,7 +258,7 @@ describe("addCompileCommand#addons", () => { target .getOptions() .addons.getAvailableAddons() - .map((it: CompilerAddon) => it.name) + .map((it: CompilerAddon) => it.getName()) ).toEqual(["zip", "zap", "zup"]); }); @@ -288,7 +288,7 @@ describe("addCompileCommand#addons", () => { target .getOptions() .addons.getAvailableAddons() - .map((it: CompilerAddon) => it.name) + .map((it: CompilerAddon) => it.getName()) ).toEqual(["expected"]); }); diff --git a/packages/compiler/src/options.spec.ts b/packages/compiler/src/options.spec.ts index b8134e6a..8f88dd8a 100644 --- a/packages/compiler/src/options.spec.ts +++ b/packages/compiler/src/options.spec.ts @@ -51,7 +51,7 @@ describe("createOptions", () => { const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.getAvailableAddons(); - expect(actual.map(it => it.name)).toEqual(["addon-foo"]); + expect(actual.map(it => it.getName())).toEqual(["addon-foo"]); }); it("should return debug path w/ debug true", () => { @@ -103,7 +103,7 @@ describe("createOptions", () => { Object.entries({ one: { activate: expect.any(Function), - name: "one", + getName: expect.any(Function), }, }) ), diff --git a/packages/core/src/compiler/addons/AddonRegistry.spec.ts b/packages/core/src/compiler/addons/AddonRegistry.spec.ts index 55c86ca4..e46fd631 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.spec.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.spec.ts @@ -69,7 +69,7 @@ describe("getAddons", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAvailableAddons().map(it => it.name)).toEqual(["expected"]); + expect(testObj.getAvailableAddons().map(it => it.getName())).toEqual(["expected"]); }); it("returns addons w/ multiple addons in addon directory", () => { @@ -100,7 +100,7 @@ describe("getAddons", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAvailableAddons().map(it => it.name)).toEqual(["one", "two", "three"]); + expect(testObj.getAvailableAddons().map(it => it.getName())).toEqual(["one", "two", "three"]); }); it("returns valid addons w/ invalid and valid addons in addon directory", () => { @@ -123,7 +123,7 @@ describe("getAddons", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAvailableAddons().map(it => it.name)).toEqual(["expected"]); + expect(testObj.getAvailableAddons().map(it => it.getName())).toEqual(["expected"]); }); it("returns no addons w/ empty files in addon directory", () => { diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index 5e855f1c..679ec2be 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -90,7 +90,7 @@ export class AddonRegistry { reporter.reportDiagnostic(new WarnMessage(`Duplicate addon name "${name}" in "${addonsDir}".`)); } if (name && activator && !map.has(name)) { - map.set(name, { name, activate: activator }); + map.set(name, { getName: () => name, activate: activator }); } }); } diff --git a/packages/core/src/compiler/addons/CompilerAddon.ts b/packages/core/src/compiler/addons/CompilerAddon.ts index 82282461..04718514 100644 --- a/packages/core/src/compiler/addons/CompilerAddon.ts +++ b/packages/core/src/compiler/addons/CompilerAddon.ts @@ -8,6 +8,6 @@ import { AddonContext } from "@quatico/websmith-api"; export interface CompilerAddon { - name: string; + getName: () => string; activate: (context: AddonContext) => void; } diff --git a/packages/core/src/compiler/addons/addon-resolver.spec.ts b/packages/core/src/compiler/addons/addon-resolver.spec.ts index 8bbcb4d6..d27f4445 100644 --- a/packages/core/src/compiler/addons/addon-resolver.spec.ts +++ b/packages/core/src/compiler/addons/addon-resolver.spec.ts @@ -35,7 +35,7 @@ describe("createResolver", () => { const actual = resolve(["one"]); expect(actual[0].activate).toEqual(expect.any(Function)); - expect(actual[0].name).toBe("one"); + expect(actual[0].getName()).toBe("one"); expect(actual).toHaveLength(1); }); @@ -53,7 +53,7 @@ describe("createResolver", () => { const actual = resolve(["DOESNOTEXIST", "one"]); expect(actual[0].activate).toEqual(expect.any(Function)); - expect(actual[0].name).toBe("one"); + expect(actual[0].getName()).toBe("one"); expect(actual).toHaveLength(1); }); diff --git a/packages/core/src/compiler/addons/addon-resolver.ts b/packages/core/src/compiler/addons/addon-resolver.ts index 4c72e767..c76e78a9 100644 --- a/packages/core/src/compiler/addons/addon-resolver.ts +++ b/packages/core/src/compiler/addons/addon-resolver.ts @@ -37,7 +37,7 @@ export const resolveName = (name: string, localPath: string, system: ts.System): return { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access activate: addonModule.activate, - name, + getName: () => name, } as CompilerAddon; } catch (ignored) { return undefined; diff --git a/packages/test/src/bar-addon.test.ts b/packages/test/src/bar-addon.test.ts index 153e2e9d..be770bbf 100644 --- a/packages/test/src/bar-addon.test.ts +++ b/packages/test/src/bar-addon.test.ts @@ -12,7 +12,7 @@ describe("test-project-foo", () => { it("should install addon successfully", () => { const testObj = compilationEnv("__TEST__").addAddon("foo-addon", join(__dirname, "../test-data/addons")); - const actual = testObj.getActiveAddons().map(it => it.name); + const actual = testObj.getActiveAddons().map(it => it.getName()); expect(actual).toContain("foo-addon"); }); diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index e6baa323..6e16e1a0 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -86,7 +86,7 @@ describe("compilationEnv#addons", () => { it("should yield addon with valid addon source", () => { const testObj = compilationEnv("/target").addAddon("expected-addon", { "addon.ts": `export const activate = () => {};` }); - const actual = testObj.getActiveAddons().map(it => it.name); + const actual = testObj.getActiveAddons().map(it => it.getName()); expect(actual).toEqual(["expected-addon"]); }); @@ -105,7 +105,7 @@ describe("compilationEnv#addons", () => { testObj.addAddon("expected-addon"); - const actual = testObj.getActiveAddons().map(it => it.name); + const actual = testObj.getActiveAddons().map(it => it.getName()); expect(actual).toEqual(["expected-addon"]); }); @@ -117,7 +117,7 @@ describe("compilationEnv#addons", () => { testObj.addAddons(["expected-addon1", "expected-addon2"]); - const actual = testObj.getActiveAddons().map(it => it.name); + const actual = testObj.getActiveAddons().map(it => it.getName()); expect(actual).toEqual(["expected-addon1", "expected-addon2"]); }); @@ -129,7 +129,7 @@ describe("compilationEnv#addons", () => { testObj.addAddons(["expected-addon1", "expected-addon2"], "./custom-addons-folder/"); - const actual = testObj.getActiveAddons().map(it => it.name); + const actual = testObj.getActiveAddons().map(it => it.getName()); expect(actual).toEqual(["expected-addon1", "expected-addon2"]); }); diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 1955c2da..056c00b4 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -97,7 +97,7 @@ export class CompilationEnv { public getActiveAddon(addonName: string): CompilerAddon | undefined { return this.getAddonRegistry() .getAvailableAddons() - .find((it: CompilerAddon) => it.name === addonName); + .find((it: CompilerAddon) => it.getName() === addonName); } public getActiveAddons(): CompilerAddon[] { diff --git a/packages/webpack/src/options.spec.ts b/packages/webpack/src/options.spec.ts index 16f73d2e..0208e06e 100644 --- a/packages/webpack/src/options.spec.ts +++ b/packages/webpack/src/options.spec.ts @@ -48,7 +48,7 @@ describe("createOptions", () => { const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.getAvailableAddons(); - expect(actual.map(it => it.name)).toEqual(["addon-foo"]); + expect(actual.map(it => it.getName())).toEqual(["addon-foo"]); }); it("should return debug path w/ debug true", () => { @@ -96,7 +96,7 @@ describe("createOptions", () => { Object.entries({ one: { activate: expect.any(Function), - name: "one", + getName: expect.any(Function), }, }) ), From a45581a9dbc0cc4441cadbcf8c3ac734b78a4832 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 16:56:49 +0200 Subject: [PATCH 21/52] r Renames setupProjectFromXXX method to addProjectFromXXX to be aligned with addProjectFile API --- packages/test/src/bar-addon.test.ts | 2 +- .../src/compilation/environment.spec.ts | 32 +++++++++---------- .../testing/src/compilation/environment.ts | 4 +-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/test/src/bar-addon.test.ts b/packages/test/src/bar-addon.test.ts index be770bbf..ca17502f 100644 --- a/packages/test/src/bar-addon.test.ts +++ b/packages/test/src/bar-addon.test.ts @@ -39,7 +39,7 @@ describe("test-project-foo", () => { }); it("should compile source project from disk", () => { - const actual = compilationEnv("__TEST__").setupProjectFromDisk("test-project-foo", join(__dirname, "../test-data/projects")).compile(); + const actual = compilationEnv("__TEST__").addProjectFromDisk("test-project-foo", join(__dirname, "../test-data/projects")).compile(); expect(actual.getCompiledFile("foo.js")!.getContent()).toMatchInlineSnapshot(` "export const foo = () => { diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index 6e16e1a0..907f64c5 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -137,7 +137,7 @@ describe("compilationEnv#addons", () => { describe("compilationEnv#projects", () => { it("should yield empty project with non-existing path", () => { - const testObj = compilationEnv("/target").setupProjectFromDisk("/does-not-exist"); + const testObj = compilationEnv("/target").addProjectFromDisk("/does-not-exist"); const actual = testObj.getProjectFiles(); @@ -145,7 +145,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with project source and file names", () => { - const testObj = compilationEnv("/target").setupProjectFromSource({ + const testObj = compilationEnv("/target").addProjectFromSource({ "index.ts": `export * from "./target";`, "target.ts": `export class Target {}`, }); @@ -157,7 +157,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with project source and relative paths", () => { - const testObj = compilationEnv("/target").setupProjectFromSource({ + const testObj = compilationEnv("/target").addProjectFromSource({ "./expected/index.ts": `export * from "./target";`, "./expected/target.ts": `export class Target {}`, }); @@ -168,7 +168,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with project source and relative src paths", () => { - const testObj = compilationEnv("/target").setupProjectFromSource({ + const testObj = compilationEnv("/target").addProjectFromSource({ "./src/index.ts": `export * from "./target";`, "./src/target.ts": `export class Target {}`, }); @@ -179,7 +179,7 @@ describe("compilationEnv#projects", () => { }); it("should yield project with project source and absolute paths", () => { - const testObj = compilationEnv("/target").setupProjectFromSource({ + const testObj = compilationEnv("/target").addProjectFromSource({ "/target/src/index.ts": `export * from "./target";`, "/target/src/target.ts": `export class Target {}`, }); @@ -190,7 +190,7 @@ describe("compilationEnv#projects", () => { }); it("should yield empty project with invalid absolute paths", () => { - const testObj = compilationEnv("/target").setupProjectFromSource({ + const testObj = compilationEnv("/target").addProjectFromSource({ // buildDir is missing in absolute paths "/whatever-path/index.ts": `export * from "./target";`, "/whatever-path/target.ts": `export class Target {}`, @@ -209,7 +209,7 @@ describe("compilationEnv#projects", () => { testObj.getSystem().writeFile("/test-projects/expected-project/src/target.ts", `export class Target {}`); testObj.getSystem().writeFile("/test-projects/expected-project/tsconfig.json", `{}`); - testObj.setupProjectFromDisk("expected-project"); + testObj.addProjectFromDisk("expected-project"); const actual = testObj.getProjectFiles(); @@ -223,7 +223,7 @@ describe("compilationEnv#projects", () => { testObj.getSystem().writeFile("/test-projects/expected-project2/src/index.ts", `export * from "./two";`); testObj.getSystem().writeFile("/test-projects/expected-project2/src/two.ts", `export class Two {}`); - testObj.setupProjectFromDisk("expected-project1").setupProjectFromDisk("expected-project2"); + testObj.addProjectFromDisk("expected-project1").addProjectFromDisk("expected-project2"); const actual = testObj.getProjectFiles(); @@ -237,7 +237,7 @@ describe("compilationEnv#projects", () => { testObj.getSystem().writeFile("/custom-projects/expected-project/src/target.ts", `export class Target {}`); testObj.getSystem().writeFile("/custom-projects/expected-project/tsconfig.json", `{}`); - testObj.setupProjectFromDisk("expected-project", "../custom-projects/"); + testObj.addProjectFromDisk("expected-project", "../custom-projects/"); const actual = testObj.getProjectFiles(); @@ -246,7 +246,7 @@ describe("compilationEnv#projects", () => { it("should yield project and add file with file name", () => { const testObj = compilationEnv("/target") - .setupProjectFromDisk("expected-project") + .addProjectFromDisk("expected-project") .addProjectFile("index.ts", `export * from "./target";`) .addProjectFile("target.ts", `export class Target {}`); @@ -258,7 +258,7 @@ describe("compilationEnv#projects", () => { it("should yield project and add files with relative paths", () => { const testObj = compilationEnv("/target") - .setupProjectFromDisk("expected-project") + .addProjectFromDisk("expected-project") .addProjectFile("./expected-dir/index.ts", `export * from "./target";`) .addProjectFile("./expected-dir/target.ts", `export class Target {}`); @@ -269,7 +269,7 @@ describe("compilationEnv#projects", () => { it("should yield project and add files with relative src paths", () => { const testObj = compilationEnv("/target") - .setupProjectFromDisk("expected-project") + .addProjectFromDisk("expected-project") .addProjectFile("./src/index.ts", `export * from "./target";`) .addProjectFile("./src/target.ts", `export class Target {}`); @@ -280,7 +280,7 @@ describe("compilationEnv#projects", () => { it("should yield project and add files with absolute paths", () => { const testObj = compilationEnv("/target") - .setupProjectFromDisk("expected-project") + .addProjectFromDisk("expected-project") .addProjectFile("/target/expected-project/index.ts", `export * from "./target";`) .addProjectFile("/target/expected-project/target.ts", `export class Target {}`); @@ -291,7 +291,7 @@ describe("compilationEnv#projects", () => { it("should yield empty project with invalid absolute paths added", () => { const testObj = compilationEnv("/target") - .setupProjectFromDisk("expected-project") + .addProjectFromDisk("expected-project") .addProjectFile("/expected-project/index.ts", `export * from "./target";`) .addProjectFile("/expected-project/target.ts", `export class Target {}`); @@ -361,7 +361,7 @@ describe("compilationEnv#compiled", () => { it("should yield compiled files with late project setup and compile", () => { const testObj = compilationEnv("/target") - .setupProjectFromSource({ + .addProjectFromSource({ "index.ts": `export * from './target';`, "target.ts": `export class Target {}`, }) @@ -374,7 +374,7 @@ describe("compilationEnv#compiled", () => { it("should yield compiled files with project", () => { const testObj = compilationEnv("/target") - .setupProjectFromSource({ + .addProjectFromSource({ "index.ts": `export * from './target';`, "target.ts": `export class Target {}`, }) diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 056c00b4..576b072b 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -169,7 +169,7 @@ export class CompilationEnv { * @param source optional source files to install * @returns this instance */ - public setupProjectFromSource(source: Record): this { + public addProjectFromSource(source: Record): this { this.addFiles( Object.entries(source).reduce((acc: Record, [filePath, content]) => { acc[resolveProjectPath(this.system, this.buildDir, filePath)] = content; @@ -187,7 +187,7 @@ export class CompilationEnv { * @param projectsSourceDir optional path to the source directory to install * @returns this instance */ - public setupProjectFromDisk(projectName: string, projectsSourceDir?: string): this { + public addProjectFromDisk(projectName: string, projectsSourceDir?: string): this { const projectsSourcePath = resolveProjectPath(this.system, this.rootDir, projectsSourceDir ?? DEFAULT_PROJECTS_SOURCE_DIR); const sourceFs = this.system.directoryExists(projectsSourcePath) ? this.system : ts.sys; copyDirectory( From a4416b12577e41b4998ee17e7cb7dcd4f33ccab1 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 17:20:20 +0200 Subject: [PATCH 22/52] e Removes testUrls from jest.configs --- jest.config.js | 1 - packages/api/jest.config.js | 2 +- packages/compiler/jest.config.js | 1 - packages/core/jest.config.js | 1 - packages/examples/jest.config.js | 8 ++------ packages/testing/jest.config.js | 1 - 6 files changed, 3 insertions(+), 11 deletions(-) diff --git a/jest.config.js b/jest.config.js index 9fb039d6..ee0920cf 100644 --- a/jest.config.js +++ b/jest.config.js @@ -19,7 +19,6 @@ module.exports = { prettierPath: null, setupFilesAfterEnv: ["/jest.setup.ts"], testRegex: "src/.*spec\\.(tsx?)$", - testEnvironmentOptions: { url: "http://localhost/" }, transform: { "^.+\\.(js|ts)$": [ "@swc/jest", diff --git a/packages/api/jest.config.js b/packages/api/jest.config.js index 96b01212..25e5f143 100644 --- a/packages/api/jest.config.js +++ b/packages/api/jest.config.js @@ -9,9 +9,9 @@ module.exports = { coverageDirectory: "coverage", coveragePathIgnorePatterns: ["index.ts"], moduleFileExtensions: ["ts", "js", "json", "node"], + prettierPath: null, testRegex: "src/.*spec\\.(js|ts)$", setupFilesAfterEnv: ["/../../jest.setup.ts"], - testEnvironmentOptions: { url: "http://localhost/" }, transform: { "^.+\\.(js|ts)$": [ "@swc/jest", diff --git a/packages/compiler/jest.config.js b/packages/compiler/jest.config.js index 54e0d24d..41f741f6 100644 --- a/packages/compiler/jest.config.js +++ b/packages/compiler/jest.config.js @@ -17,7 +17,6 @@ module.exports = { prettierPath: null, testRegex: "src/.*\\.spec\\.(j|t)s$", setupFilesAfterEnv: ["/../../jest.setup.ts"], - testEnvironmentOptions: { url: "http://localhost/" }, transform: { "^.+\\.(js|ts)$": [ "@swc/jest", diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js index 628b1439..982dc386 100644 --- a/packages/core/jest.config.js +++ b/packages/core/jest.config.js @@ -16,7 +16,6 @@ module.exports = { setupFilesAfterEnv: ["/../../jest.setup.ts"], testRegex: "src/.*(test|spec)\\.(js|ts)$", testTimeout: 15000, - testEnvironmentOptions: { url: "http://localhost/" }, transform: { "^.+\\.(js|ts)$": [ "@swc/jest", diff --git a/packages/examples/jest.config.js b/packages/examples/jest.config.js index e5b18449..a963d490 100644 --- a/packages/examples/jest.config.js +++ b/packages/examples/jest.config.js @@ -5,17 +5,14 @@ * --------------------------------------------------------------------------------------------- */ module.exports = { - collectCoverageFrom: ["./src/**/*.ts"], - coverageDirectory: "coverage", - coveragePathIgnorePatterns: ["index.ts"], moduleFileExtensions: ["ts", "js", "json", "node"], moduleNameMapper: { "@quatico/websmith-api": "/../api/src", "@quatico/websmith-testing": "/../testing/src", }, - testRegex: "src/.*spec\\.(js|ts)$", + prettierPath: null, + testRegex: "tests/.*test\\.(js|ts)$", setupFilesAfterEnv: ["/../../jest.setup.ts"], - testEnvironmentOptions: { url: "http://localhost/" }, transform: { "^.+\\.(js|ts)$": [ "@swc/jest", @@ -28,5 +25,4 @@ module.exports = { }, ], }, - resetMocks: true, }; diff --git a/packages/testing/jest.config.js b/packages/testing/jest.config.js index fb935a6e..3c5c4946 100644 --- a/packages/testing/jest.config.js +++ b/packages/testing/jest.config.js @@ -17,7 +17,6 @@ module.exports = { prettierPath: null, testRegex: "src/.*spec\\.(js|ts)$", setupFilesAfterEnv: ["/../../jest.setup.ts"], - testEnvironmentOptions: { url: "http://localhost/" }, transform: { "^.+\\.(js|ts)$": [ "@swc/jest", From c583ed481d5052d527debed3e7285f735dcafc7c Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 17:25:12 +0200 Subject: [PATCH 23/52] F Introduces getPaths() and getContents() mapping API for ProjectFiles --- .../src/compilation/environment.spec.ts | 45 ++++++++++--------- .../testing/src/compilation/environment.ts | 17 +++++-- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index 907f64c5..c477110e 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-call */ /* * --------------------------------------------------------------------------------------------- * Copyright (c) Quatico Solutions AG. All rights reserved. @@ -141,7 +142,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual).toEqual([]); + expect(actual).toHaveLength(0); }); it("should yield project with project source and file names", () => { @@ -152,8 +153,8 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); - expect(actual.map(it => it.getContent())).toEqual([`export * from "./target";`, `export class Target {}`]); + expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); + expect(actual.getContents()).toEqual([`export * from "./target";`, `export class Target {}`]); }); it("should yield project with project source and relative paths", () => { @@ -164,7 +165,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/expected/index.ts", "/target/src/expected/target.ts"]); + expect(actual.getPaths()).toEqual(["/target/src/expected/index.ts", "/target/src/expected/target.ts"]); }); it("should yield project with project source and relative src paths", () => { @@ -175,7 +176,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); + expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); }); it("should yield project with project source and absolute paths", () => { @@ -186,7 +187,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); + expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); }); it("should yield empty project with invalid absolute paths", () => { @@ -198,7 +199,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual).toEqual([]); + expect(actual).toHaveLength(0); expect(testObj.getSystem().readFile("/whatever-path/index.ts")).toBe(`export * from "./target";`); expect(testObj.getSystem().readFile("/whatever-path/target.ts")).toBe(`export class Target {}`); }); @@ -213,7 +214,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts", "/target/tsconfig.json"]); + expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/target.ts", "/target/tsconfig.json"]); }); it("should yield projects with multiple projects in default projects path", () => { @@ -227,8 +228,8 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/one.ts", "/target/src/two.ts"]); - expect(actual.map(it => it.getContent())).toEqual([`export * from "./two";`, `export class One {}`, `export class Two {}`]); + expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/one.ts", "/target/src/two.ts"]); + expect(actual.getContents()).toEqual([`export * from "./two";`, `export class One {}`, `export class Two {}`]); }); it("should yield project with single project in custom projects path", () => { @@ -241,7 +242,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts", "/target/tsconfig.json"]); + expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/target.ts", "/target/tsconfig.json"]); }); it("should yield project and add file with file name", () => { @@ -252,8 +253,8 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); - expect(actual.map(it => it.getContent())).toEqual([`export * from "./target";`, `export class Target {}`]); + expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); + expect(actual.getContents()).toEqual([`export * from "./target";`, `export class Target {}`]); }); it("should yield project and add files with relative paths", () => { @@ -264,7 +265,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/expected-dir/index.ts", "/target/src/expected-dir/target.ts"]); + expect(actual.getPaths()).toEqual(["/target/src/expected-dir/index.ts", "/target/src/expected-dir/target.ts"]); }); it("should yield project and add files with relative src paths", () => { @@ -275,7 +276,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); + expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/target.ts"]); }); it("should yield project and add files with absolute paths", () => { @@ -286,7 +287,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); + expect(actual.getPaths()).toEqual(["/target/expected-project/index.ts", "/target/expected-project/target.ts"]); }); it("should yield empty project with invalid absolute paths added", () => { @@ -297,7 +298,7 @@ describe("compilationEnv#projects", () => { const actual = testObj.getProjectFiles(); - expect(actual).toEqual([]); + expect(actual).toHaveLength(0); expect(testObj.getSystem().readDirectory("/")).toEqual(["/expected-project/index.ts", "/expected-project/target.ts"]); }); }); @@ -308,7 +309,7 @@ describe("compilationEnv#compiled", () => { const actual = testObj.getCompiledFiles(); - expect(actual).toEqual([]); + expect(actual).toHaveLength(0); }); it("should yield no compiled files with existing project but no compile", () => { @@ -321,13 +322,13 @@ describe("compilationEnv#compiled", () => { const actual = testObj.getCompiledFiles(); - expect(actual).toEqual([]); + expect(actual).toHaveLength(0); }); it("should yield no compiled files and empty result with empty project and compile", () => { const testObj = compilationEnv("/target").compile(); - expect(testObj.getCompiledFiles()).toEqual([]); + expect(testObj.getCompiledFiles()).toHaveLength(0); expect(testObj.hasEmitSkipped()).toBe(false); expect(testObj.getEmittedFiles()).toEqual([]); expect(testObj.getDiagnostics()).toEqual([]); @@ -341,7 +342,7 @@ describe("compilationEnv#compiled", () => { }, }).compile(); - expect(testObj.getCompiledFiles().map(it => it.getPath())).toEqual(["/target/dist/index.js", "/target/dist/target.js"]); + expect(testObj.getCompiledFiles().getPaths()).toEqual(["/target/dist/index.js", "/target/dist/target.js"]); expect(testObj.hasEmitSkipped()).toBe(false); expect(testObj.getEmittedFiles()).toEqual(["/target/dist/index.js", "/target/dist/target.js"]); expect(testObj.getDiagnostics()).toEqual([]); @@ -369,7 +370,7 @@ describe("compilationEnv#compiled", () => { const actual = testObj.getCompiledFiles(); - expect(actual.map(it => it.getPath())).toEqual(["/target/dist/index.js", "/target/dist/target.js"]); + expect(actual.getPaths()).toEqual(["/target/dist/index.js", "/target/dist/target.js"]); }); it("should yield compiled files with project", () => { diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 576b072b..b2077758 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -204,8 +204,8 @@ export class CompilationEnv { return this; } - public getProjectFiles(): ProjectFile[] { - return this.system.readDirectory(this.rootDir).map(it => projectFile(this.system, this.buildDir, it)); + public getProjectFiles(): ProjectFiles { + return projectFiles(this.system.readDirectory(this.rootDir).map(it => projectFile(this.system, this.buildDir, it))); } public getProjectFile(filePath: string): ProjectFile | undefined { @@ -245,8 +245,9 @@ export class CompilationEnv { return resolveProjectPath(this.system, this.rootDir, this.getCompilerOptions().project.outDir ?? DEFAULT_OUT_DIR); } - public getCompiledFiles(): ProjectFile[] { - return this.system.readDirectory(this.getCompiledDir()).map(it => projectFile(this.getSystem(), this.buildDir, it)); + public getCompiledFiles(): ProjectFiles { + return projectFiles(this.system.readDirectory(this.getCompiledDir()).map(it => projectFile(this.getSystem(), this.buildDir, it))); + } public getCompiledFile(filePath: string): ProjectFile | undefined { @@ -324,6 +325,8 @@ export type CompilationOptions = { virtual?: boolean; }; +export type ProjectFiles = ProjectFile[] & { getPaths: () => string[], getContents: () => string[] }; + export interface ProjectFile { getPath(): string; getContent(): string | undefined; @@ -352,4 +355,10 @@ const isSourceFile = (filePath: string): boolean => filePath.endsWith(".ts") || const isFiles = (source?: string | Record): source is Record => typeof source === "object"; +const projectFiles = (result: ProjectFile[]): ProjectFiles => { + return Object.assign(result, { getPaths: () => result.map(it => it.getPath()), getContents: () => result.map(it => it.getContent()!) }); +} + export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => new CompilationEnv(rootDir, options); + + From 3151c905cd8df884363b449bddd99795e2e3d468 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Thu, 2 May 2024 17:30:27 +0200 Subject: [PATCH 24/52] d Updates README to document initial testing API --- packages/testing/README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/testing/README.md b/packages/testing/README.md index 6408530c..3c69d1ba 100644 --- a/packages/testing/README.md +++ b/packages/testing/README.md @@ -73,14 +73,24 @@ import { compilationEnv } from '@quatico/websmith-testing'; describe('FoobarAddon', () => { it('should compile', () => { - const results = compilationEnv('/target').addProject("expected-project", { + const results = compilationEnv('/target').addProjectFromSource({ "./foo-bar/index.ts": `export * from "./target";`, "./foo-bar/target.ts": `export class Target {}`, }) - .addAddons(['foobar-addon'], "../addons") + .addAddons(['foobar-addon'], join(__dirname, "../addons")) .compile(); - // expect the compilation results + const actual = results.getCompiledFiles(); + + expect(actual.getContents()).toEquals([ + "export * from './target';", + "export class Target {}" + ]); + + expect(results.getCompiledFile("target.js").getContent()).toMatchInlineSnapshot(` + "export class Target {} + " + `); }); }); ``` From 640ee17c65d96ba954de73f5846bdb64705ec588 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Fri, 3 May 2024 00:11:22 +0200 Subject: [PATCH 25/52] F Show off how to use the testing API with the addon examples package --- .../core/src/compiler/addons/CompilerAddon.ts | 2 + .../examples/tests/example-generator.test.ts | 29 ++++++++ .../examples/tests/example-processor.test.ts | 73 +++++++++++++++++++ .../tests/example-result-processor.test.ts | 68 +++++++++++++++++ .../tests/example-transformer.test.ts | 37 ++++++++++ .../tests/export-yaml-generator.test.ts | 30 ++++++++ packages/testing/package.json | 1 + .../testing/src/compilation/copy-directory.ts | 4 +- .../testing/src/compilation/environment.ts | 22 ++++-- pnpm-lock.yaml | 3 + 10 files changed, 259 insertions(+), 10 deletions(-) create mode 100644 packages/examples/tests/example-generator.test.ts create mode 100644 packages/examples/tests/example-processor.test.ts create mode 100644 packages/examples/tests/example-result-processor.test.ts create mode 100644 packages/examples/tests/example-transformer.test.ts create mode 100644 packages/examples/tests/export-yaml-generator.test.ts diff --git a/packages/core/src/compiler/addons/CompilerAddon.ts b/packages/core/src/compiler/addons/CompilerAddon.ts index 04718514..f1e0e132 100644 --- a/packages/core/src/compiler/addons/CompilerAddon.ts +++ b/packages/core/src/compiler/addons/CompilerAddon.ts @@ -8,6 +8,8 @@ import { AddonContext } from "@quatico/websmith-api"; export interface CompilerAddon { + // FIXME: We need to add the sourceDir of the addon + sourceDir?: string; getName: () => string; activate: (context: AddonContext) => void; } diff --git a/packages/examples/tests/example-generator.test.ts b/packages/examples/tests/example-generator.test.ts new file mode 100644 index 00000000..5925655d --- /dev/null +++ b/packages/examples/tests/example-generator.test.ts @@ -0,0 +1,29 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import { join } from "path"; +import { compilationEnv, type CompilationEnv } from "../../testing/lib"; + +describe("example-generator", () => { + let testObj: CompilationEnv; + beforeAll(() => { + testObj = compilationEnv("./__TEST__").addAddon("example-generator", join(__dirname, "../addons")); + }); + + afterEach(() => { + testObj.cleanUp("project"); + }); + + it("should create additional input files and add them to compilation", () => { + testObj + .addProjectFromSource({ + "bar.ts": `console.log("Hello, Bar!");`, + "foo.ts": `export class Foo {}`, + }) + .compile(); + + const actual = testObj.getCompiledFiles().getPaths(); + + expect(actual).toEqual(["/__TEST__/dist/bar.js", "/__TEST__/dist/foo.js", "/__TEST__/dist/foo-added.js"]); + }); +}); diff --git a/packages/examples/tests/example-processor.test.ts b/packages/examples/tests/example-processor.test.ts new file mode 100644 index 00000000..510f509c --- /dev/null +++ b/packages/examples/tests/example-processor.test.ts @@ -0,0 +1,73 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import { compilationEnv, type CompilationEnv } from "@quatico/websmith-testing"; +import { join } from "path"; + +describe("example-processor", () => { + let testObj: CompilationEnv; + beforeAll(() => { + testObj = compilationEnv("./__TEST__").addAddon("example-processor", join(__dirname, "../addons")); + }); + + afterEach(() => { + testObj.cleanUp("project"); + }); + + it("should add export to functions named 'foobar' with single function", () => { + testObj + .addProjectFromSource({ + "target.ts": ` + function foobar(): void { + console.log("Hello, Foo!"); + } + `, + }) + .compile(); + + const actual = testObj.getCompiledFile("target.js")!.getContent(); + + expect(actual).toMatchInlineSnapshot(` + "export function foobar() { + console.log("Hello, Foo!"); + } + " + `); + }); + + it("should not export functions named differently", () => { + testObj + .addProjectFromSource({ + "target.ts": ` + function whatever(): void { + console.log("Hello, Foo!"); + } + `, + }) + .compile(); + + const actual = testObj.getCompiledFile("target.js")!.getContent(); + + expect(actual).toMatchInlineSnapshot(` + "function whatever() { + console.log("Hello, Foo!"); + } + " + `); + }); + + it("should not export arrow functions with name 'foobar'", () => { + testObj + .addProjectFromSource({ + "target.ts": `const foobar = (): void => console.log("Hello, Foo!");`, + }) + .compile(); + + const actual = testObj.getCompiledFile("target.js")!.getContent(); + + expect(actual).toMatchInlineSnapshot(` + "const foobar = () => console.log("Hello, Foo!"); + " + `); + }); +}); diff --git a/packages/examples/tests/example-result-processor.test.ts b/packages/examples/tests/example-result-processor.test.ts new file mode 100644 index 00000000..7f0fb0a4 --- /dev/null +++ b/packages/examples/tests/example-result-processor.test.ts @@ -0,0 +1,68 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import { compilationEnv, type CompilationEnv } from "@quatico/websmith-testing"; +import { join } from "path"; + +describe("example-result-processor", () => { + let testObj: CompilationEnv; + beforeAll(() => { + testObj = compilationEnv("./__TEST__").addAddon("example-result-processor", join(__dirname, "../addons")); + }); + + afterEach(() => { + testObj.cleanUp("project"); + }); + + it("should create a JSON file with single function names", () => { + testObj + .addProjectFromSource({ + "target.ts": ` + function expected(): void { + console.log("Hello, Foo!"); + } + `, + }) + .compile(); + + const actual = testObj.getCompiledFile("named-functions.json")!.getContent()!; + + expect(JSON.parse(actual)).toMatchObject({ target: ["expected"] }); + }); + + it("should create a JSON file without function names for arrow functions", () => { + testObj + .addProjectFromSource({ + "target.ts": ` + const baz = (): void => console.log("Hello, Baz!"); + `, + }) + .compile(); + + const actual = testObj.getCompiledFile("named-functions.json")!.getContent()!; + + expect(JSON.parse(actual)).toMatchObject({ target: [] }); + }); + + it("should create a JSON file with multiple function names", () => { + testObj + .addProjectFromSource({ + "target.ts": ` + function foobar(): void { + console.log("Hello, Foo!"); + } + function barfoo(): void { + console.log("Hello, Bar!"); + } + const baz = (): void => console.log("Hello, Baz!"); + `, + "other.ts": `const zip = () => console.log("Hello, World!");`, + }) + .compile(); + + const actual = testObj.getCompiledFile("named-functions.json")!.getContent()!; + + expect(JSON.parse(actual)).toMatchObject({ target: ["foobar", "barfoo"], other: [] }); + }); +}); diff --git a/packages/examples/tests/example-transformer.test.ts b/packages/examples/tests/example-transformer.test.ts new file mode 100644 index 00000000..925f1462 --- /dev/null +++ b/packages/examples/tests/example-transformer.test.ts @@ -0,0 +1,37 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import { compilationEnv, type CompilationEnv } from "@quatico/websmith-testing"; +import { join } from "path"; + +describe("example-transformer", () => { + let testObj: CompilationEnv; + beforeAll(() => { + testObj = compilationEnv("./__TEST__").addAddon("example-transformer", join(__dirname, "../addons")); + }); + + afterEach(() => { + testObj.cleanUp("project"); + }); + + it("should replace 'foobar' with 'barfoo'", () => { + testObj + .addProjectFromSource({ + "target.ts": ` + function foobar(): void { + console.log("Hello, Foo!"); + } + `, + }) + .compile(); + + const actual = testObj.getCompiledFile("target.js")!.getContent(); + + expect(actual).toMatchInlineSnapshot(` + "function barfoo() { + console.log("Hello, Foo!"); + } + " + `); + }); +}); diff --git a/packages/examples/tests/export-yaml-generator.test.ts b/packages/examples/tests/export-yaml-generator.test.ts new file mode 100644 index 00000000..3bb9b6f5 --- /dev/null +++ b/packages/examples/tests/export-yaml-generator.test.ts @@ -0,0 +1,30 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import { compilationEnv, type CompilationEnv } from "@quatico/websmith-testing"; +import { join } from "path"; + +// FIXME: This test is failing because the virtual mock for this addon needs the actual sourceDir +describe.skip("export-yaml-generator", () => { + let testObj: CompilationEnv; + beforeAll(() => { + testObj = compilationEnv("./__TEST__").addAddon("export-yaml-generator", join(__dirname, "../addons")); + }); + + afterEach(() => { + testObj.cleanUp("project"); + }); + + it("should create additional input files and add them to compilation", () => { + testObj + .addProjectFromSource({ + "bar.ts": `console.log("Hello, Bar!");`, + "foo.ts": `export class Foo {}`, + }) + .compile(); + + const actual = testObj.getCompiledFiles().getPaths(); + + expect(actual).toEqual(["/__TEST__/dist/bar.js", "/__TEST__/dist/foo.js", "/__TEST__/dist/foo-added.js"]); + }); +}); diff --git a/packages/testing/package.json b/packages/testing/package.json index 8d068be1..8ee44e41 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -32,6 +32,7 @@ "dist": "pnpm clean && pnpm lint && pnpm test && cross-env-shell NODE_ENV=production \"pnpm build\"" }, "dependencies": { + "@quatico/websmith-api": "workspace:^", "@quatico/websmith-core": "workspace:^", "require-from-string": "^2.0.2" }, diff --git a/packages/testing/src/compilation/copy-directory.ts b/packages/testing/src/compilation/copy-directory.ts index 6a79aff9..3c299c7e 100644 --- a/packages/testing/src/compilation/copy-directory.ts +++ b/packages/testing/src/compilation/copy-directory.ts @@ -10,7 +10,7 @@ import ts from "typescript"; type SourcePath = { system: ts.System; path: string; - kind: "project" | "addon"; + kind: "project" | "addons"; }; type SourceFilePath = SourcePath & { @@ -26,7 +26,7 @@ export const copyDirectory = (source: SourcePath, target: TargetPath) => { const { system: srcSystem, path: srcPath, kind } = source; // Throw an error if the source directory does not exist for addons - if (kind === "addon" && !srcSystem.directoryExists(srcPath)) { + if (kind === "addons" && !srcSystem.directoryExists(srcPath)) { throw new Error(`Source directory ${srcPath} does not exist.`); } diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index b2077758..73b00865 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -5,6 +5,7 @@ * --------------------------------------------------------------------------------------------- */ import { AddonRegistry, Compiler, createBrowserSystem, type CompilerAddon, type CompilerOptions } from "@quatico/websmith-core"; +import { rmdirSync } from "fs"; import { basename, dirname, extname, isAbsolute, join } from "path"; import requireFromString from "require-from-string"; import ts from "typescript"; @@ -76,10 +77,14 @@ export class CompilationEnv { return this.virtual; } - public cleanUp(path?: string): this { - const target = path ?? this.rootDir; - if (this.system.fileExists(target)) { - this.system.readDirectory(target).forEach(it => this.system.deleteFile!(it)); + public cleanUp(options: "project" | "addons" | "all" = "all"): this { + const target = options === "project" ? this.getProjectDir() : options === "addons" ? this.getAddonsDir() : this.rootDir; + if (this.system.directoryExists(target)) { + if (this.isVirtual()) { + this.system.readDirectory(target).forEach(it => this.system.deleteFile!(it)); + } else { + rmdirSync(target, { recursive: true }); + } } return this; } @@ -137,7 +142,7 @@ export class CompilationEnv { } else { const addonsSourceDir = resolveProjectPath(this.system, this.rootDir, join(addonSource ?? DEFAULT_ADDONS_SOURCE_DIR, addonName)); const sourceFs = this.system.directoryExists(addonsSourceDir) ? this.system : ts.sys; - copyDirectory({ system: sourceFs, path: addonsSourceDir, kind: "addon" }, { system: this.system, path: addonTargetPath }); + copyDirectory({ system: sourceFs, path: addonsSourceDir, kind: "addons" }, { system: this.system, path: addonTargetPath }); } this.compileAddons(this.getAddonRegistry().getAddonsDir()); @@ -150,7 +155,7 @@ export class CompilationEnv { const addonsSourceDirPath = resolveProjectPath(this.system, this.rootDir, addonsSourceDir ?? DEFAULT_ADDONS_SOURCE_DIR); const sourceFs = this.system.directoryExists(addonsSourceDirPath) ? this.system : ts.sys; addonNames.forEach(addon => { - copyDirectory({ system: sourceFs, path: join(addonsSourceDirPath, addon), kind: "addon" }, { system: this.system, path: addonsDir }); + copyDirectory({ system: sourceFs, path: join(addonsSourceDirPath, addon), kind: "addons" }, { system: this.system, path: addonsDir }); }); this.compileAddons(addonsDir); this.getAddonRegistry().refresh(); @@ -267,7 +272,7 @@ export class CompilationEnv { ...compileOptions(this.system, { buildDir: curDir, }), - project: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES5 }, + project: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES5, esModuleInterop: true }, tsconfig: { fileNames: this.system.readDirectory(curDir).filter(isSourceFile), options: {}, errors: [] }, }, this.system @@ -282,7 +287,8 @@ export class CompilationEnv { .forEach(it => { jest.mock( extname(it).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) ? it.replace(extname(it), "") : it, - () => requireFromString(this.system.readFile(it)!), + // FIXME: replace __dirname with the actual sourceDir of the addon + () => requireFromString(this.system.readFile(it)!, __dirname), { virtual: true } ); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86006e4a..b6af7e0d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -508,6 +508,9 @@ importers: packages/testing: dependencies: + '@quatico/websmith-api': + specifier: workspace:^ + version: link:../api '@quatico/websmith-core': specifier: workspace:^ version: link:../core From 2c741708b4db88b2ef199d2d530c401c72bbaebb Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Fri, 3 May 2024 00:29:26 +0200 Subject: [PATCH 26/52] t Don't add empty projects to your test data --- packages/testing/src/compilation/environment.spec.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index c477110e..831e0988 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -138,7 +138,7 @@ describe("compilationEnv#addons", () => { describe("compilationEnv#projects", () => { it("should yield empty project with non-existing path", () => { - const testObj = compilationEnv("/target").addProjectFromDisk("/does-not-exist"); + const testObj = compilationEnv("/target").addProjectFromDisk("whatever", "/does-not-exist"); const actual = testObj.getProjectFiles(); @@ -245,9 +245,8 @@ describe("compilationEnv#projects", () => { expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/target.ts", "/target/tsconfig.json"]); }); - it("should yield project and add file with file name", () => { + it("should yield project and add files with file name", () => { const testObj = compilationEnv("/target") - .addProjectFromDisk("expected-project") .addProjectFile("index.ts", `export * from "./target";`) .addProjectFile("target.ts", `export class Target {}`); @@ -259,7 +258,6 @@ describe("compilationEnv#projects", () => { it("should yield project and add files with relative paths", () => { const testObj = compilationEnv("/target") - .addProjectFromDisk("expected-project") .addProjectFile("./expected-dir/index.ts", `export * from "./target";`) .addProjectFile("./expected-dir/target.ts", `export class Target {}`); @@ -270,7 +268,6 @@ describe("compilationEnv#projects", () => { it("should yield project and add files with relative src paths", () => { const testObj = compilationEnv("/target") - .addProjectFromDisk("expected-project") .addProjectFile("./src/index.ts", `export * from "./target";`) .addProjectFile("./src/target.ts", `export class Target {}`); @@ -281,7 +278,6 @@ describe("compilationEnv#projects", () => { it("should yield project and add files with absolute paths", () => { const testObj = compilationEnv("/target") - .addProjectFromDisk("expected-project") .addProjectFile("/target/expected-project/index.ts", `export * from "./target";`) .addProjectFile("/target/expected-project/target.ts", `export class Target {}`); @@ -292,7 +288,6 @@ describe("compilationEnv#projects", () => { it("should yield empty project with invalid absolute paths added", () => { const testObj = compilationEnv("/target") - .addProjectFromDisk("expected-project") .addProjectFile("/expected-project/index.ts", `export * from "./target";`) .addProjectFile("/expected-project/target.ts", `export class Target {}`); From 5a11f32bcee8cc15285af68c3008dcdba019e1d1 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Fri, 3 May 2024 01:13:37 +0200 Subject: [PATCH 27/52] E Upgrades project dependencies --- package.json | 14 +- packages/api/package.json | 8 +- packages/compiler/package.json | 16 +- packages/core/package.json | 14 +- packages/examples/package.json | 14 +- packages/test/jest.config.js | 1 - packages/test/package.json | 15 +- packages/testing/package.json | 12 +- .../__data__/module-test/package.json | 12 +- packages/webpack-test/package.json | 16 +- packages/webpack/package.json | 16 +- pnpm-lock.yaml | 2070 +++++++++-------- 12 files changed, 1141 insertions(+), 1067 deletions(-) diff --git a/package.json b/package.json index fcea1ce1..70be48bc 100644 --- a/package.json +++ b/package.json @@ -40,12 +40,12 @@ "@cucumber/gherkin": "^28.0.0", "@eslint/js": "^9.1.1", "@nrwl/nx-cloud": "18.0.1", - "@nx/eslint-plugin": "^18.3.3", + "@nx/eslint-plugin": "^18.3.4", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/glob": "^8.1.0", "@types/jest": "^29.5.12", - "@types/node": "^20.12.7", + "@types/node": "20", "commander": "^12.0.0", "concurrently": "^8.2.2", "create-hash": "1.2.0", @@ -54,15 +54,15 @@ "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^28.3.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-testing-library": "^6.2.2", - "globals": "^15.0.0", + "globals": "^15.1.0", "husky": "9.0.11", "jest": "^29.7.0", "license-check-and-add": "4.0.5", - "memfs": "^4.8.2", - "nx": "^18.3.3", + "memfs": "^4.9.2", + "nx": "^18.3.4", "path": "0.12.7", "prettier": "^3.2.5", "quill-delta": "^5.1.0", @@ -71,7 +71,7 @@ "ts-node": "^10.9.2", "tslib": "2.6.2", "typescript": "5.4.5", - "typescript-eslint": "^7.7.1", + "typescript-eslint": "^7.8.0", "webpack": "^5.91.0" }, "pnpm": { diff --git a/packages/api/package.json b/packages/api/package.json index 74114221..028fb563 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@eslint/js": "^9.1.1", - "@nx/eslint-plugin": "^18.3.3", + "@nx/eslint-plugin": "^18.3.4", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", @@ -43,15 +43,15 @@ "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^28.3.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-testing-library": "^6.2.2", - "globals": "^15.0.0", + "globals": "^15.1.0", "jest": "^29.7.0", "prettier": "^3.2.5", "rimraf": "5.0.5", "typescript": "5.4.5", - "typescript-eslint": "^7.7.1" + "typescript-eslint": "^7.8.0" }, "peerDependencies": { "typescript": "5.x" diff --git a/packages/compiler/package.json b/packages/compiler/package.json index 3eb11ff9..74b75c95 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -35,31 +35,31 @@ }, "devDependencies": { "@eslint/js": "^9.1.1", - "@nx/eslint-plugin": "^18.3.3", - "@quatico/websmith-testing": "workspace:^", + "@nx/eslint-plugin": "^18.3.4", + "@quatico/websmith-testing": "workspace:*", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", "@types/minimist": "^1.2.5", - "@types/node": "^20.12.7", + "@types/node": "20", "concurrently": "^8.2.2", "cross-env": "7.0.3", "eslint": "^9.1.1", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^28.3.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-testing-library": "^6.2.2", - "globals": "^15.0.0", + "globals": "^15.1.0", "jest": "^29.7.0", "prettier": "^3.2.5", "rimraf": "5.0.5", - "typescript-eslint": "^7.7.1" + "typescript-eslint": "^7.8.0" }, "dependencies": { - "@quatico/websmith-api": "workspace:^", - "@quatico/websmith-core": "workspace:^", + "@quatico/websmith-api": "workspace:*", + "@quatico/websmith-core": "workspace:*", "commander": "^12.0.0", "minimist": "^1.2.8", "ts-node": "^10.9.2", diff --git a/packages/core/package.json b/packages/core/package.json index aaf1cd6b..65ba5a81 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -32,31 +32,31 @@ }, "devDependencies": { "@eslint/js": "^9.1.1", - "@nx/eslint-plugin": "^18.3.3", + "@nx/eslint-plugin": "^18.3.4", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", "@types/lodash": "^4.17.0", - "@types/node": "^20.12.7", + "@types/node": "20", "concurrently": "^8.2.2", "cross-env": "7.0.3", "eslint": "^9.1.1", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^28.3.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-testing-library": "^6.2.2", - "globals": "^15.0.0", + "globals": "^15.1.0", "jest": "^29.7.0", - "memfs": "^4.8.2", + "memfs": "^4.9.2", "prettier": "^3.2.5", "rimraf": "5.0.5", "typescript": "5.4.5", - "typescript-eslint": "^7.7.1" + "typescript-eslint": "^7.8.0" }, "dependencies": { - "@quatico/websmith-api": "workspace:^", + "@quatico/websmith-api": "workspace:*", "create-hash": "1.2.0", "lodash": "^4.17.21", "path": "0.12.7" diff --git a/packages/examples/package.json b/packages/examples/package.json index 352e1ec9..36f3f956 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -19,28 +19,28 @@ }, "devDependencies": { "@eslint/js": "^9.1.1", - "@nx/eslint-plugin": "^18.3.3", - "@quatico/websmith-api": "workspace:^", - "@quatico/websmith-testing": "workspace:^", + "@nx/eslint-plugin": "^18.3.4", + "@quatico/websmith-api": "workspace:*", + "@quatico/websmith-testing": "workspace:*", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", - "@types/node": "^20.12.7", + "@types/node": "20", "concurrently": "^8.2.2", "cross-env": "7.0.3", "eslint": "^9.1.1", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^28.3.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-testing-library": "^6.2.2", - "globals": "^15.0.0", + "globals": "^15.1.0", "jest": "^29.7.0", "prettier": "^3.2.5", "rimraf": "5.0.5", "typescript": "5.4.5", - "typescript-eslint": "^7.7.1" + "typescript-eslint": "^7.8.0" }, "peerDependencies": { "typescript": "5.x" diff --git a/packages/test/jest.config.js b/packages/test/jest.config.js index bc540fe0..84a3f91d 100644 --- a/packages/test/jest.config.js +++ b/packages/test/jest.config.js @@ -9,7 +9,6 @@ module.exports = { moduleFileExtensions: ["ts", "js", "json", "node"], moduleNameMapper: { "@quatico/websmith-core": "/../core/src", - "@quatico/websmith-compiler": "/../compiler/src", "@quatico/websmith-testing": "/../testing/src", }, prettierPath: null, diff --git a/packages/test/package.json b/packages/test/package.json index 1133c5f1..dad8545a 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -15,29 +15,28 @@ }, "devDependencies": { "@eslint/js": "^9.1.1", - "@nx/eslint-plugin": "^18.3.3", - "@quatico/websmith-compiler": "workspace:^", - "@quatico/websmith-core": "workspace:^", - "@quatico/websmith-testing": "workspace:^", + "@nx/eslint-plugin": "^18.3.4", + "@quatico/websmith-core": "workspace:*", + "@quatico/websmith-testing": "workspace:*", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", - "@types/node": "^20.12.7", + "@types/node": "20", "concurrently": "^8.2.2", "cross-env": "7.0.3", "eslint": "^9.1.1", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^28.3.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-testing-library": "^6.2.2", - "globals": "^15.0.0", + "globals": "^15.1.0", "jest": "^29.7.0", "path": "0.12.7", "prettier": "^3.2.5", "rimraf": "5.0.5", "typescript": "5.4.5", - "typescript-eslint": "^7.7.1" + "typescript-eslint": "^7.8.0" } } \ No newline at end of file diff --git a/packages/testing/package.json b/packages/testing/package.json index 8ee44e41..ca57d802 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -32,13 +32,13 @@ "dist": "pnpm clean && pnpm lint && pnpm test && cross-env-shell NODE_ENV=production \"pnpm build\"" }, "dependencies": { - "@quatico/websmith-api": "workspace:^", - "@quatico/websmith-core": "workspace:^", + "@quatico/websmith-api": "workspace:*", + "@quatico/websmith-core": "workspace:*", "require-from-string": "^2.0.2" }, "devDependencies": { "@eslint/js": "^9.1.1", - "@nx/eslint-plugin": "^18.3.3", + "@nx/eslint-plugin": "^18.3.4", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", @@ -49,15 +49,15 @@ "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^28.3.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-testing-library": "^6.2.2", - "globals": "^15.0.0", + "globals": "^15.1.0", "jest": "^29.7.0", "prettier": "^3.2.5", "rimraf": "5.0.5", "typescript": "5.4.5", - "typescript-eslint": "^7.7.1" + "typescript-eslint": "^7.8.0" }, "peerDependencies": { "typescript": "5.x" diff --git a/packages/webpack-test/__data__/module-test/package.json b/packages/webpack-test/__data__/module-test/package.json index 6e5147bb..a20874ee 100644 --- a/packages/webpack-test/__data__/module-test/package.json +++ b/packages/webpack-test/__data__/module-test/package.json @@ -3,13 +3,13 @@ "version": "1.0.0", "private": true, "devDependencies": { - "@quatico/websmith-webpack": "workspace:^", - "@types/react": "18.2.79", - "@types/react-dom": "18.2.25", + "@quatico/websmith-webpack": "workspace:*", + "@types/react": "18.3.1", + "@types/react-dom": "18.3.0", "fork-ts-checker-webpack-plugin": "^9.0.2", - "react": "18.2.0", - "react-dom": "18.2.0", - "react-is": "18.2.0", + "react": "18.3.1", + "react-dom": "18.3.1", + "react-is": "18.3.1", "thread-loader": "4.0.2", "webpack": "^5.91.0", "webpack-cli": "^5.1.4" diff --git a/packages/webpack-test/package.json b/packages/webpack-test/package.json index edc9c512..aad6c2a6 100644 --- a/packages/webpack-test/package.json +++ b/packages/webpack-test/package.json @@ -15,29 +15,29 @@ }, "devDependencies": { "@eslint/js": "^9.1.1", - "@nx/eslint-plugin": "^18.3.3", - "@quatico/websmith-webpack": "workspace:^", + "@nx/eslint-plugin": "^18.3.4", + "@quatico/websmith-webpack": "workspace:*", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", - "@types/node": "^20.12.7", + "@types/node": "20", "@types/webpack": "^5.28.5", "eslint": "^9.1.1", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^28.3.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-testing-library": "^6.2.2", "fork-ts-checker-webpack-plugin": "^9.0.2", - "globals": "^15.0.0", + "globals": "^15.1.0", "jest": "^29.7.0", "prettier": "^3.2.5", - "react": "18.2.0", - "react-dom": "18.2.0", + "react": "18.3.1", + "react-dom": "18.3.1", "rimraf": "^5.0.5", "thread-loader": "4.0.2", "typescript": "5.4.5", - "typescript-eslint": "^7.7.1", + "typescript-eslint": "^7.8.0", "webpack": "^5.91.0", "webpack-cli": "^5.1.4" } diff --git a/packages/webpack/package.json b/packages/webpack/package.json index 296cc378..69f084d8 100644 --- a/packages/webpack/package.json +++ b/packages/webpack/package.json @@ -30,33 +30,33 @@ "dist": "pnpm clean && pnpm lint && pnpm test && cross-env-shell NODE_ENV=production \"pnpm build\"" }, "dependencies": { - "@quatico/websmith-api": "workspace:^", - "@quatico/websmith-core": "workspace:^" + "@quatico/websmith-api": "workspace:*", + "@quatico/websmith-core": "workspace:*" }, "devDependencies": { "@eslint/js": "^9.1.1", - "@nx/eslint-plugin": "^18.3.3", - "@quatico/websmith-testing": "workspace:^", + "@nx/eslint-plugin": "^18.3.4", + "@quatico/websmith-testing": "workspace:*", "@swc/core": "1.5.0", "@swc/jest": "0.2.36", "@types/jest": "^29.5.12", - "@types/node": "^20.12.7", + "@types/node": "20", "@types/webpack": "^5.28.5", "eslint": "^9.1.1", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^28.3.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-testing-library": "^6.2.2", "fork-ts-checker-webpack-plugin": "^9.0.2", - "globals": "^15.0.0", + "globals": "^15.1.0", "jest": "^29.7.0", "prettier": "^3.2.5", "rimraf": "^5.0.5", "thread-loader": "4.0.2", "typescript": "5.4.5", - "typescript-eslint": "^7.7.1", + "typescript-eslint": "^7.8.0", "webpack": "^5.91.0", "webpack-cli": "^5.1.4" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6af7e0d..d7a7383d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: 18.0.1 version: 18.0.1 '@nx/eslint-plugin': - specifier: ^18.3.3 - version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + specifier: ^18.3.4 + version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) '@swc/core': specifier: 1.5.0 version: 1.5.0 @@ -33,8 +33,8 @@ importers: specifier: ^29.5.12 version: 29.5.12 '@types/node': - specifier: ^20.12.7 - version: 20.12.7 + specifier: '20' + version: 20.12.8 commander: specifier: ^12.0.0 version: 12.0.0 @@ -55,13 +55,13 @@ importers: version: 9.1.0(eslint@9.1.1) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) + version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) eslint-plugin-jest: - specifier: ^28.2.0 - version: 28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5) + specifier: ^28.3.0 + version: 28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(prettier@3.2.5) @@ -69,23 +69,23 @@ importers: specifier: ^6.2.2 version: 6.2.2(eslint@9.1.1)(typescript@5.4.5) globals: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^15.1.0 + version: 15.1.0 husky: specifier: 9.0.11 version: 9.0.11 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) license-check-and-add: specifier: 4.0.5 version: 4.0.5 memfs: - specifier: ^4.8.2 - version: 4.8.2 + specifier: ^4.9.2 + version: 4.9.2 nx: - specifier: ^18.3.3 - version: 18.3.3(@swc/core@1.5.0) + specifier: ^18.3.4 + version: 18.3.4(@swc/core@1.5.0) path: specifier: 0.12.7 version: 0.12.7 @@ -103,7 +103,7 @@ importers: version: 7.8.1 ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5) + version: 10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5) tslib: specifier: 2.6.2 version: 2.6.2 @@ -111,8 +111,8 @@ importers: specifier: 5.4.5 version: 5.4.5 typescript-eslint: - specifier: ^7.7.1 - version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) + specifier: ^7.8.0 + version: 7.8.0(eslint@9.1.1)(typescript@5.4.5) webpack: specifier: ^5.91.0 version: 5.91.0(@swc/core@1.5.0) @@ -123,8 +123,8 @@ importers: specifier: ^9.1.1 version: 9.1.1 '@nx/eslint-plugin': - specifier: ^18.3.3 - version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + specifier: ^18.3.4 + version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) '@swc/core': specifier: 1.5.0 version: 1.5.0 @@ -148,13 +148,13 @@ importers: version: 9.1.0(eslint@9.1.1) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) + version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) eslint-plugin-jest: - specifier: ^28.2.0 - version: 28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5) + specifier: ^28.3.0 + version: 28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(prettier@3.2.5) @@ -162,11 +162,11 @@ importers: specifier: ^6.2.2 version: 6.2.2(eslint@9.1.1)(typescript@5.4.5) globals: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^15.1.0 + version: 15.1.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) prettier: specifier: ^3.2.5 version: 3.2.5 @@ -177,16 +177,16 @@ importers: specifier: 5.4.5 version: 5.4.5 typescript-eslint: - specifier: ^7.7.1 - version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) + specifier: ^7.8.0 + version: 7.8.0(eslint@9.1.1)(typescript@5.4.5) packages/compiler: dependencies: '@quatico/websmith-api': - specifier: workspace:^ + specifier: workspace:* version: link:../api '@quatico/websmith-core': - specifier: workspace:^ + specifier: workspace:* version: link:../core commander: specifier: ^12.0.0 @@ -196,7 +196,7 @@ importers: version: 1.2.8 ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5) + version: 10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5) tslib: specifier: 2.6.2 version: 2.6.2 @@ -208,10 +208,10 @@ importers: specifier: ^9.1.1 version: 9.1.1 '@nx/eslint-plugin': - specifier: ^18.3.3 - version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + specifier: ^18.3.4 + version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) '@quatico/websmith-testing': - specifier: workspace:^ + specifier: workspace:* version: link:../testing '@swc/core': specifier: 1.5.0 @@ -226,8 +226,8 @@ importers: specifier: ^1.2.5 version: 1.2.5 '@types/node': - specifier: ^20.12.7 - version: 20.12.7 + specifier: '20' + version: 20.12.8 concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -242,13 +242,13 @@ importers: version: 9.1.0(eslint@9.1.1) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) + version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) eslint-plugin-jest: - specifier: ^28.2.0 - version: 28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5) + specifier: ^28.3.0 + version: 28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(prettier@3.2.5) @@ -256,11 +256,11 @@ importers: specifier: ^6.2.2 version: 6.2.2(eslint@9.1.1)(typescript@5.4.5) globals: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^15.1.0 + version: 15.1.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) prettier: specifier: ^3.2.5 version: 3.2.5 @@ -268,13 +268,13 @@ importers: specifier: 5.0.5 version: 5.0.5 typescript-eslint: - specifier: ^7.7.1 - version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) + specifier: ^7.8.0 + version: 7.8.0(eslint@9.1.1)(typescript@5.4.5) packages/core: dependencies: '@quatico/websmith-api': - specifier: workspace:^ + specifier: workspace:* version: link:../api create-hash: specifier: 1.2.0 @@ -290,8 +290,8 @@ importers: specifier: ^9.1.1 version: 9.1.1 '@nx/eslint-plugin': - specifier: ^18.3.3 - version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + specifier: ^18.3.4 + version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) '@swc/core': specifier: 1.5.0 version: 1.5.0 @@ -305,8 +305,8 @@ importers: specifier: ^4.17.0 version: 4.17.0 '@types/node': - specifier: ^20.12.7 - version: 20.12.7 + specifier: '20' + version: 20.12.8 concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -321,13 +321,13 @@ importers: version: 9.1.0(eslint@9.1.1) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) + version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) eslint-plugin-jest: - specifier: ^28.2.0 - version: 28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5) + specifier: ^28.3.0 + version: 28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(prettier@3.2.5) @@ -335,14 +335,14 @@ importers: specifier: ^6.2.2 version: 6.2.2(eslint@9.1.1)(typescript@5.4.5) globals: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^15.1.0 + version: 15.1.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) memfs: - specifier: ^4.8.2 - version: 4.8.2 + specifier: ^4.9.2 + version: 4.9.2 prettier: specifier: ^3.2.5 version: 3.2.5 @@ -353,8 +353,8 @@ importers: specifier: 5.4.5 version: 5.4.5 typescript-eslint: - specifier: ^7.7.1 - version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) + specifier: ^7.8.0 + version: 7.8.0(eslint@9.1.1)(typescript@5.4.5) packages/examples: devDependencies: @@ -362,13 +362,13 @@ importers: specifier: ^9.1.1 version: 9.1.1 '@nx/eslint-plugin': - specifier: ^18.3.3 - version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + specifier: ^18.3.4 + version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) '@quatico/websmith-api': - specifier: workspace:^ + specifier: workspace:* version: link:../api '@quatico/websmith-testing': - specifier: workspace:^ + specifier: workspace:* version: link:../testing '@swc/core': specifier: 1.5.0 @@ -380,8 +380,8 @@ importers: specifier: ^29.5.12 version: 29.5.12 '@types/node': - specifier: ^20.12.7 - version: 20.12.7 + specifier: '20' + version: 20.12.8 concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -396,13 +396,13 @@ importers: version: 9.1.0(eslint@9.1.1) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) + version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) eslint-plugin-jest: - specifier: ^28.2.0 - version: 28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5) + specifier: ^28.3.0 + version: 28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(prettier@3.2.5) @@ -410,11 +410,11 @@ importers: specifier: ^6.2.2 version: 6.2.2(eslint@9.1.1)(typescript@5.4.5) globals: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^15.1.0 + version: 15.1.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) prettier: specifier: ^3.2.5 version: 3.2.5 @@ -425,8 +425,8 @@ importers: specifier: 5.4.5 version: 5.4.5 typescript-eslint: - specifier: ^7.7.1 - version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) + specifier: ^7.8.0 + version: 7.8.0(eslint@9.1.1)(typescript@5.4.5) packages/test: devDependencies: @@ -434,16 +434,16 @@ importers: specifier: ^9.1.1 version: 9.1.1 '@nx/eslint-plugin': - specifier: ^18.3.3 - version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + specifier: ^18.3.4 + version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) '@quatico/websmith-compiler': - specifier: workspace:^ + specifier: workspace:* version: link:../compiler '@quatico/websmith-core': - specifier: workspace:^ + specifier: workspace:* version: link:../core '@quatico/websmith-testing': - specifier: workspace:^ + specifier: workspace:* version: link:../testing '@swc/core': specifier: 1.5.0 @@ -455,8 +455,8 @@ importers: specifier: ^29.5.12 version: 29.5.12 '@types/node': - specifier: ^20.12.7 - version: 20.12.7 + specifier: '20' + version: 20.12.8 concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -471,13 +471,13 @@ importers: version: 9.1.0(eslint@9.1.1) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) + version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) eslint-plugin-jest: - specifier: ^28.2.0 - version: 28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5) + specifier: ^28.3.0 + version: 28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(prettier@3.2.5) @@ -485,11 +485,11 @@ importers: specifier: ^6.2.2 version: 6.2.2(eslint@9.1.1)(typescript@5.4.5) globals: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^15.1.0 + version: 15.1.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) path: specifier: 0.12.7 version: 0.12.7 @@ -503,16 +503,16 @@ importers: specifier: 5.4.5 version: 5.4.5 typescript-eslint: - specifier: ^7.7.1 - version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) + specifier: ^7.8.0 + version: 7.8.0(eslint@9.1.1)(typescript@5.4.5) packages/testing: dependencies: '@quatico/websmith-api': - specifier: workspace:^ + specifier: workspace:* version: link:../api '@quatico/websmith-core': - specifier: workspace:^ + specifier: workspace:* version: link:../core require-from-string: specifier: ^2.0.2 @@ -522,8 +522,8 @@ importers: specifier: ^9.1.1 version: 9.1.1 '@nx/eslint-plugin': - specifier: ^18.3.3 - version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + specifier: ^18.3.4 + version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) '@swc/core': specifier: 1.5.0 version: 1.5.0 @@ -550,13 +550,13 @@ importers: version: 9.1.0(eslint@9.1.1) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) + version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) eslint-plugin-jest: - specifier: ^28.2.0 - version: 28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5) + specifier: ^28.3.0 + version: 28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(prettier@3.2.5) @@ -564,11 +564,11 @@ importers: specifier: ^6.2.2 version: 6.2.2(eslint@9.1.1)(typescript@5.4.5) globals: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^15.1.0 + version: 15.1.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) prettier: specifier: ^3.2.5 version: 3.2.5 @@ -579,26 +579,26 @@ importers: specifier: 5.4.5 version: 5.4.5 typescript-eslint: - specifier: ^7.7.1 - version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) + specifier: ^7.8.0 + version: 7.8.0(eslint@9.1.1)(typescript@5.4.5) packages/webpack: dependencies: '@quatico/websmith-api': - specifier: workspace:^ + specifier: workspace:* version: link:../api '@quatico/websmith-core': - specifier: workspace:^ + specifier: workspace:* version: link:../core devDependencies: '@eslint/js': specifier: ^9.1.1 version: 9.1.1 '@nx/eslint-plugin': - specifier: ^18.3.3 - version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + specifier: ^18.3.4 + version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) '@quatico/websmith-testing': - specifier: workspace:^ + specifier: workspace:* version: link:../testing '@swc/core': specifier: 1.5.0 @@ -610,8 +610,8 @@ importers: specifier: ^29.5.12 version: 29.5.12 '@types/node': - specifier: ^20.12.7 - version: 20.12.7 + specifier: '20' + version: 20.12.8 '@types/webpack': specifier: ^5.28.5 version: 5.28.5(@swc/core@1.5.0)(webpack-cli@5.1.4(webpack@5.91.0)) @@ -623,13 +623,13 @@ importers: version: 9.1.0(eslint@9.1.1) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) + version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) eslint-plugin-jest: - specifier: ^28.2.0 - version: 28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5) + specifier: ^28.3.0 + version: 28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(prettier@3.2.5) @@ -640,11 +640,11 @@ importers: specifier: ^9.0.2 version: 9.0.2(typescript@5.4.5)(webpack@5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4)) globals: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^15.1.0 + version: 15.1.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) prettier: specifier: ^3.2.5 version: 3.2.5 @@ -658,8 +658,8 @@ importers: specifier: 5.4.5 version: 5.4.5 typescript-eslint: - specifier: ^7.7.1 - version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) + specifier: ^7.8.0 + version: 7.8.0(eslint@9.1.1)(typescript@5.4.5) webpack: specifier: ^5.91.0 version: 5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4) @@ -673,10 +673,10 @@ importers: specifier: ^9.1.1 version: 9.1.1 '@nx/eslint-plugin': - specifier: ^18.3.3 - version: 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + specifier: ^18.3.4 + version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) '@quatico/websmith-webpack': - specifier: workspace:^ + specifier: workspace:* version: link:../webpack '@swc/core': specifier: 1.5.0 @@ -688,8 +688,8 @@ importers: specifier: ^29.5.12 version: 29.5.12 '@types/node': - specifier: ^20.12.7 - version: 20.12.7 + specifier: '20' + version: 20.12.8 '@types/webpack': specifier: ^5.28.5 version: 5.28.5(@swc/core@1.5.0)(webpack-cli@5.1.4(webpack@5.91.0)) @@ -701,10 +701,10 @@ importers: version: 9.1.0(eslint@9.1.1) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) + version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)) eslint-plugin-jest: - specifier: ^28.2.0 - version: 28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5) + specifier: ^28.3.0 + version: 28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(prettier@3.2.5) @@ -715,20 +715,20 @@ importers: specifier: ^9.0.2 version: 9.0.2(typescript@5.4.5)(webpack@5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4(webpack@5.91.0))) globals: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^15.1.0 + version: 15.1.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) prettier: specifier: ^3.2.5 version: 3.2.5 react: - specifier: 18.2.0 - version: 18.2.0 + specifier: 18.3.1 + version: 18.3.1 react-dom: - specifier: 18.2.0 - version: 18.2.0(react@18.2.0) + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) rimraf: specifier: ^5.0.5 version: 5.0.5 @@ -739,8 +739,8 @@ importers: specifier: 5.4.5 version: 5.4.5 typescript-eslint: - specifier: ^7.7.1 - version: 7.7.1(eslint@9.1.1)(typescript@5.4.5) + specifier: ^7.8.0 + version: 7.8.0(eslint@9.1.1)(typescript@5.4.5) webpack: specifier: ^5.91.0 version: 5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4(webpack@5.91.0)) @@ -751,26 +751,26 @@ importers: packages/webpack-test/__data__/module-test: devDependencies: '@quatico/websmith-webpack': - specifier: workspace:^ + specifier: workspace:* version: link:../../../webpack '@types/react': - specifier: 18.2.79 - version: 18.2.79 + specifier: 18.3.1 + version: 18.3.1 '@types/react-dom': - specifier: 18.2.25 - version: 18.2.25 + specifier: 18.3.0 + version: 18.3.0 fork-ts-checker-webpack-plugin: specifier: ^9.0.2 version: 9.0.2(typescript@5.4.5)(webpack@5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4)) react: - specifier: 18.2.0 - version: 18.2.0 + specifier: 18.3.1 + version: 18.3.1 react-dom: - specifier: 18.2.0 - version: 18.2.0(react@18.2.0) + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) react-is: - specifier: 18.2.0 - version: 18.2.0 + specifier: 18.3.1 + version: 18.3.1 thread-loader: specifier: 4.0.2 version: 4.0.2(webpack@5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4)) @@ -783,10 +783,6 @@ importers: packages: - '@aashutoshrathi/word-wrap@1.2.6': - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -799,12 +795,12 @@ packages: resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} engines: {node: '>=6.9.0'} - '@babel/core@7.24.4': - resolution: {integrity: sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==} + '@babel/core@7.24.5': + resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.24.4': - resolution: {integrity: sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==} + '@babel/generator@7.24.5': + resolution: {integrity: sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==} engines: {node: '>=6.9.0'} '@babel/helper-annotate-as-pure@7.22.5': @@ -819,8 +815,8 @@ packages: resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.24.4': - resolution: {integrity: sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==} + '@babel/helper-create-class-features-plugin@7.24.5': + resolution: {integrity: sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -848,16 +844,16 @@ packages: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.23.0': - resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} + '@babel/helper-member-expression-to-functions@7.24.5': + resolution: {integrity: sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==} engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.24.3': resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.23.3': - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + '@babel/helper-module-transforms@7.24.5': + resolution: {integrity: sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -866,8 +862,8 @@ packages: resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.24.0': - resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} + '@babel/helper-plugin-utils@7.24.5': + resolution: {integrity: sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==} engines: {node: '>=6.9.0'} '@babel/helper-remap-async-to-generator@7.22.20': @@ -882,49 +878,49 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-simple-access@7.22.5': - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + '@babel/helper-simple-access@7.24.5': + resolution: {integrity: sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==} engines: {node: '>=6.9.0'} '@babel/helper-skip-transparent-expression-wrappers@7.22.5': resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} engines: {node: '>=6.9.0'} - '@babel/helper-split-export-declaration@7.22.6': - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + '@babel/helper-split-export-declaration@7.24.5': + resolution: {integrity: sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.24.1': resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.22.20': - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + '@babel/helper-validator-identifier@7.24.5': + resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==} engines: {node: '>=6.9.0'} '@babel/helper-validator-option@7.23.5': resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.22.20': - resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} + '@babel/helper-wrap-function@7.24.5': + resolution: {integrity: sha512-/xxzuNvgRl4/HLNKvnFwdhdgN3cpLxgLROeLDl83Yx0AJ1SGvq1ak0OszTOjDfiB8Vx03eJbeDWh9r+jCCWttw==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.24.4': - resolution: {integrity: sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==} + '@babel/helpers@7.24.5': + resolution: {integrity: sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.2': - resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} + '@babel/highlight@7.24.5': + resolution: {integrity: sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.24.4': - resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==} + '@babel/parser@7.24.5': + resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.4': - resolution: {integrity: sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==} + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.5': + resolution: {integrity: sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1102,8 +1098,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.24.4': - resolution: {integrity: sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==} + '@babel/plugin-transform-block-scoping@7.24.5': + resolution: {integrity: sha512-sMfBc3OxghjC95BkYrYocHL3NaOplrcaunblzwXhGmlPwpmfsxr4vK+mBBt49r+S240vahmv+kUxkeKgs+haCw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1120,8 +1116,8 @@ packages: peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.24.1': - resolution: {integrity: sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==} + '@babel/plugin-transform-classes@7.24.5': + resolution: {integrity: sha512-gWkLP25DFj2dwe9Ck8uwMOpko4YsqyfZJrOmqqcegeDYEbp7rmn4U6UQZNj08UF6MaX39XenSpKRCvpDRBtZ7Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1132,8 +1128,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.24.1': - resolution: {integrity: sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==} + '@babel/plugin-transform-destructuring@7.24.5': + resolution: {integrity: sha512-SZuuLyfxvsm+Ah57I/i1HVjveBENYK9ue8MJ7qkc7ndoNjqquJiElzA7f5yaAXjyW2hKojosOTAQQRX50bPSVg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1252,8 +1248,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.24.1': - resolution: {integrity: sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==} + '@babel/plugin-transform-object-rest-spread@7.24.5': + resolution: {integrity: sha512-7EauQHszLGM3ay7a161tTQH7fj+3vVM/gThlz5HpFtnygTxjrlvoeq7MPVA1Vy9Q555OB8SnAOsMkLShNkkrHA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1270,14 +1266,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.24.1': - resolution: {integrity: sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==} + '@babel/plugin-transform-optional-chaining@7.24.5': + resolution: {integrity: sha512-xWCkmwKT+ihmA6l7SSTpk8e4qQl/274iNbSKRRS8mpqFR32ksy36+a+LWY8OXCCEefF8WFlnOHVsaDI2231wBg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-parameters@7.24.1': - resolution: {integrity: sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==} + '@babel/plugin-transform-parameters@7.24.5': + resolution: {integrity: sha512-9Co00MqZ2aoky+4j2jhofErthm6QVLKbpQrvz20c3CH9KQCLHyNB+t2ya4/UrRpQGR+Wrwjg9foopoeSdnHOkA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1288,8 +1284,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.24.1': - resolution: {integrity: sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==} + '@babel/plugin-transform-private-property-in-object@7.24.5': + resolution: {integrity: sha512-JM4MHZqnWR04jPMujQDTBVRnqxpLLpx2tkn7iPn+Hmsc0Gnb79yvRWOkvqFOx3Z7P7VxiRIR22c4eGSNj87OBQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1342,14 +1338,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typeof-symbol@7.24.1': - resolution: {integrity: sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==} + '@babel/plugin-transform-typeof-symbol@7.24.5': + resolution: {integrity: sha512-UTGnhYVZtTAjdwOTzT+sCyXmTn8AhaxOS/MjG9REclZ6ULHWF9KoCZur0HSGU7hk8PdBFKKbYe6+gqdXWz84Jg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.24.4': - resolution: {integrity: sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==} + '@babel/plugin-transform-typescript@7.24.5': + resolution: {integrity: sha512-E0VWu/hk83BIFUWnsKZ4D81KXjN5L3MobvevOHErASk9IPwKHOkTgvqzvNo1yP/ePJWqqK2SpUR5z+KQbl6NVw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1378,8 +1374,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.24.4': - resolution: {integrity: sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==} + '@babel/preset-env@7.24.5': + resolution: {integrity: sha512-UGK2ifKtcC8i5AI4cH+sbLLuLc2ktYSFJgBAXorKAsHUZmrQ1q6aQ6i3BvU24wWs2AAKqQB6kq3N9V9Gw1HiMQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1398,20 +1394,20 @@ packages: '@babel/regjsgen@0.8.0': resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} - '@babel/runtime@7.24.4': - resolution: {integrity: sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==} + '@babel/runtime@7.24.5': + resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} engines: {node: '>=6.9.0'} '@babel/template@7.24.0': resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.24.1': - resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} + '@babel/traverse@7.24.5': + resolution: {integrity: sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==} engines: {node: '>=6.9.0'} - '@babel/types@7.24.0': - resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + '@babel/types@7.24.5': + resolution: {integrity: sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@0.2.3': @@ -1570,6 +1566,24 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jsonjoy.com/base64@1.1.1': + resolution: {integrity: sha512-LnFjVChaGY8cZVMwAIMjvA1XwQjZ/zIXHyh28IyJkyNkzof4Dkm1+KN9UIm3lHhREH4vs7XwZ0NpkZKnwOtEfg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pack@1.0.3': + resolution: {integrity: sha512-Q0SPAdmK6s5Fe3e1kcNvwNyk6e2+CxM8XZdGbf4abZG7nUO05KSie3/iX29loTBuY+75uVP6RixDSPVpotfzmQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/util@1.1.2': + resolution: {integrity: sha512-HOGa9wtE6LEz2I5mMQ2pMSjth85PmD71kPbsecs02nEUq3/Kw0wRK3gmZn5BCEB8mFLXByqPxjHgApoMwIPMKQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1582,32 +1596,32 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@nrwl/devkit@18.3.3': - resolution: {integrity: sha512-3zZLE1vfwsNie7qjVUt9lqaM1slU0RTr/dW+Yt/2lxe8Peu6f8bnCM1Pf3kSlzoxQroctfocRtVHFXJsAuAt4g==} + '@nrwl/devkit@18.3.4': + resolution: {integrity: sha512-Fty9Huqm12OYueU3uLJl3uvBUl5BvEyPfvw8+rLiNx9iftdEattM8C+268eAbIRRSLSOVXlWsJH4brlc6QZYYw==} - '@nrwl/eslint-plugin-nx@18.3.3': - resolution: {integrity: sha512-ARqwcA2n2NN+8ATrooZtPbaW5fb9WSjDFZaI8RdphMXFnPrEkZnMpbrjFpLTj+wc1R6hIgTcYbli6fv4Gfbo3Q==} + '@nrwl/eslint-plugin-nx@18.3.4': + resolution: {integrity: sha512-IiBAxWgOZC4dIqnirpoRJ0YvDeR9HjlOyKna2CZoUj4Dr5uYOiNHbxVbfLPhsIenRLEbjttCxrA9Mm9k++bdjA==} - '@nrwl/js@18.3.3': - resolution: {integrity: sha512-7Wtv5kpeMWUDBUFu5go49HM/S8vDrtMOvZf9xnUcnjsFDReWe8XIEkTWudZDbzID3X4T6WQAftzj2Ov6k566lQ==} + '@nrwl/js@18.3.4': + resolution: {integrity: sha512-oyiMoxzDVGQe5E4UFGO/WAOU211HEIdRxSEOfs1lPhvA8lKbUa0IWDqPOugNws/YHAr+vUTU3sZDJ3uU3RJuYQ==} '@nrwl/nx-cloud@18.0.1': resolution: {integrity: sha512-uYVxoOXf0xlWJX8O5GBWajmIeL0PfIGvfqtvVNVnl7C6FiZRbmKEhXkWxEDekI6Jq+mI1G86o7d5YsIzq6e36A==} - '@nrwl/tao@18.3.3': - resolution: {integrity: sha512-f/PUDLpSMEObiLQ5sIDySJM+5DxSCNunkxxbY1R9rmQ1cFcgrHaXIHQqbSj91mMa3mmtbKACk8u1LbI+oQV0Tg==} + '@nrwl/tao@18.3.4': + resolution: {integrity: sha512-+7KsDYmGj1cvNaXZcjSYOPN1h17hsGFBtVX7MqnpJLLkQTUhKg2rQxqyluzshJ+RoDUVtYPGyHg1AizlB66RIA==} hasBin: true - '@nrwl/workspace@18.3.3': - resolution: {integrity: sha512-9Giuec9l3PpS8mekD00W9kBIKmWRpQSkp+/RvYmc+7kKtVC+Uj/kc68exBOanVgq6zKzYrn+FqHWHGWnHxp+ww==} + '@nrwl/workspace@18.3.4': + resolution: {integrity: sha512-ziPHZcSYj46aPYrRHaKu56/SmYCijLT5vIm/UaoWD5v5Fy5CRigO/ezUImsHGHMEZWfHt44s4jsv7QdJWAXe7w==} - '@nx/devkit@18.3.3': - resolution: {integrity: sha512-FtkZ6mA5//vEA5lcbT80m080ROVacHYV5F1peztTRA+IY2JZGJoqx425kn5ylDO8aCSAIAwcn2qIdhI8BnpG3Q==} + '@nx/devkit@18.3.4': + resolution: {integrity: sha512-M3htxl5WvlNKK5KNOndCAApbyBCZNTFFs+rtdwvudNZk5+84zAAPaWzSoX9C4XLAW78/f98LzF68/ch05aN12A==} peerDependencies: nx: '>= 16 <= 19' - '@nx/eslint-plugin@18.3.3': - resolution: {integrity: sha512-ww3r8VRlzJXOBRG+qCTd+VXHRKxiIrOH+cIokTtuzGrnCXWEMSPO5Ts6z/Jsbb0xAcfZ39WUnxuDZdKbp4aHqA==} + '@nx/eslint-plugin@18.3.4': + resolution: {integrity: sha512-rGQX/w+qexGWOLjHECZeZ2RDgaKEUvQW+zGBNlw/5u7tZcTYUpG10VG1j+BrwBZ1gT9YV1b/0IUYdwdEo1NNwA==} peerDependencies: '@typescript-eslint/parser': ^6.13.2 || ^7.0.0 eslint-config-prettier: ^9.0.0 @@ -1615,76 +1629,76 @@ packages: eslint-config-prettier: optional: true - '@nx/js@18.3.3': - resolution: {integrity: sha512-e8u56oG0mlTVz48EeH0C7txX0GeLYN0o4mK1LDAMIHQa4tKefNfwrdqHaZBiVqFOPopeFtqi8s0kqce5prwCaw==} + '@nx/js@18.3.4': + resolution: {integrity: sha512-+MPacp/B09e5QwaFQBkev9pW862ZpmesqR2lUUnFAXUBKtjYVIAmhJWHOtevqC1om4OxvTsbluYHsbAkAUzlMA==} peerDependencies: verdaccio: ^5.0.4 peerDependenciesMeta: verdaccio: optional: true - '@nx/nx-darwin-arm64@18.3.3': - resolution: {integrity: sha512-NpA2/7o1uUuaocMYopX9muxKif9HlGfWaXo2UeiR918usF6xri4aUqweZbaXVc9iqCAEbVMWUsjaLYGKPXHAjw==} + '@nx/nx-darwin-arm64@18.3.4': + resolution: {integrity: sha512-MOGk9z4fIoOkJB68diH3bwoWrC8X9IzMNsz1mu0cbVfgCRAfIV3b+lMsiwQYzWal3UWW5DE5Rkss4F8whiV5Uw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@nx/nx-darwin-x64@18.3.3': - resolution: {integrity: sha512-aydPLbc7DeceJ6szRf6DLT4ERoPvwfWyFiGXdAlEZYWhjEuNZLeG8K6jA3yHeWltKfX/qJqhnyKbnubBNzBKlQ==} + '@nx/nx-darwin-x64@18.3.4': + resolution: {integrity: sha512-tSzPRnNB3QdPM+KYiIuRCUtyCwcuIRC95FfP0ZB3WvfDeNxJChEAChNqmCMDE4iFvZhGuze8WqkJuIVdte+lyQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@nx/nx-freebsd-x64@18.3.3': - resolution: {integrity: sha512-sEYEWsK/fwC1l7wzls7RNOjhmrooH0lK0mpgj1vDXesLBSZ7k+pddAqaHFECN4QXBSbHZI2PWOEhbnIH+Errsg==} + '@nx/nx-freebsd-x64@18.3.4': + resolution: {integrity: sha512-bjSPak/d+bcR95/pxHMRhnnpHc6MnrQcG6f5AjX15Esm4JdrdQKPBmG1RybuK0WKSyD5wgVhkAGc/QQUom9l8g==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@nx/nx-linux-arm-gnueabihf@18.3.3': - resolution: {integrity: sha512-B9GGMkrrzwiAfvew22x85ITO9TiNxbgRbKJQWQaoopNpXrnSWpY8WTNxpDT24fwV1qdQfsPKcY3F4O0NOUgPRA==} + '@nx/nx-linux-arm-gnueabihf@18.3.4': + resolution: {integrity: sha512-/1HnUL7jhH0S7PxJqf6R1pk3QlAU22GY89EQV9fd+RDUtp7IyzaTlkebijTIqfxlSjC4OO3bPizaxEaxdd3uKQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@nx/nx-linux-arm64-gnu@18.3.3': - resolution: {integrity: sha512-1EucHf5/0JeqZmhritqkpEdOcdo9Dl32gpFvhNfS6kCAYmaDlEl4zqedz3VIoj4C7+C0pV3mcRO9qB9H7GM5bQ==} + '@nx/nx-linux-arm64-gnu@18.3.4': + resolution: {integrity: sha512-g/2IaB2bZTKaBNPEf9LxtIXb1XHdhh3VO9PnePIrwkkixPMLN0dTxT5Sttt75lvLP3EU1AUR5w3Aaz2Q1mYtWA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@nx/nx-linux-arm64-musl@18.3.3': - resolution: {integrity: sha512-HPgOgnYYLPVCBEaAkSEGPGzZqTDCiyCAF/qtvx5z0f1U/hZYb1ubgxw70ogY82Cafr7X4gQBz5k4/ZCnoCXlOQ==} + '@nx/nx-linux-arm64-musl@18.3.4': + resolution: {integrity: sha512-MgfKLoEF6I1cCS+0ooFLEjJSSVdCYyCT9Q96IHRJntAEL8u/0GR2OUoBoLC+q1lnbIkJr/uqTJxA2Jh+sJTIbA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@nx/nx-linux-x64-gnu@18.3.3': - resolution: {integrity: sha512-FgYTQ3VEE6EUOGtJT9riRK8IBwPGFjKS+N2mudQJn2bB/9IumUvVRYQUIX08gqGLlqZPO6uUUhUjwZY8SnjRLQ==} + '@nx/nx-linux-x64-gnu@18.3.4': + resolution: {integrity: sha512-vbHxv7m3gjthBvw50EYCtgyY0Zg5nVTaQtX+wRsmKybV2i7wHbw5zIe1aL4zHUm6TcPGbIQK+utVM+hyCqKHVA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@nx/nx-linux-x64-musl@18.3.3': - resolution: {integrity: sha512-QnWjGViR1Wj9gJXa1RJ9mXyy2/JzQ7NF2C4ulTYSH5St1HoxhkfnLsV0+uNLFEV9PSZq+2BfxmQuT8Appefv1A==} + '@nx/nx-linux-x64-musl@18.3.4': + resolution: {integrity: sha512-qIJKJCYFRLVSALsvg3avjReOjuYk91Q0hFXMJ2KaEM1Y3tdzcFN0fKBiaHexgbFIUk8zJuS4dJObTqSYMXowbg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@nx/nx-win32-arm64-msvc@18.3.3': - resolution: {integrity: sha512-Xn3LUaPsF8QkEYUVV3lc693NTCMWrfZBFXTy1cQpvLzQ+idsXQ/EGWoq93cIM3Nc2YWyblT2hHHelb8dHCZAlw==} + '@nx/nx-win32-arm64-msvc@18.3.4': + resolution: {integrity: sha512-UxC8mRkFTPdZbKFprZkiBqVw8624xU38kI0xyooxKlFpt5lccTBwJ0B7+R8p1RoWyvh2DSyFI9VvfD7lczg1lA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@nx/nx-win32-x64-msvc@18.3.3': - resolution: {integrity: sha512-t8HvOnQEiaaoTFOOIrql30NPhIwDFO7jg0Jtz3Tbneulh7ceswJp71yFHsRGGrYZ23Tgg+Sna6M9qLRGzlRGkg==} + '@nx/nx-win32-x64-msvc@18.3.4': + resolution: {integrity: sha512-/RqEjNU9hxIBxRLafCNKoH3SaB2FShf+1ZnIYCdAoCZBxLJebDpnhiyrVs0lPnMj9248JbizEMdJj1+bs/bXig==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@nx/workspace@18.3.3': - resolution: {integrity: sha512-SUJJKzOUuNnclpHHde6f6nlF+pQwMjeF026jFpWDFaNzdsADhhRulkz0GLRXB9kKszvzz2JKde9WBWnKrFZ2IQ==} + '@nx/workspace@18.3.4': + resolution: {integrity: sha512-H5HmEOWb9wnrNXfI2DhK6AmMVz1snuJvjT2jcMf9kxlVW0pKGTFW+OyHfSYq6Ni3OGWb1f9O63erLYHo45zPeA==} '@phenomnomnominal/tsquery@5.0.1': resolution: {integrity: sha512-3nVv+e2FQwsW8Aw6qTU6f+1rfcJ3hrcnvH/mu9i8YhxO+9sqbOfpL8m6PbET5+xKOlz/VSbp0RoYWYCtIsnmuA==} @@ -1771,6 +1785,7 @@ packages: '@swc/core@1.5.0': resolution: {integrity: sha512-fjADAC5gOOX54Rpcr1lF9DHLD+nPD5H/zXLtEgK2Ez3esmogT+LfHzCZtUxqetjvaMChKhQ0Pp0ZB6Hpz/tCbw==} engines: {node: '>=10'} + deprecated: Mac OS installation is broken peerDependencies: '@swc/helpers': ^0.5.0 peerDependenciesMeta: @@ -1858,8 +1873,8 @@ packages: '@types/minimist@1.2.5': resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - '@types/node@20.12.7': - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} + '@types/node@20.12.8': + resolution: {integrity: sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -1867,11 +1882,11 @@ packages: '@types/prop-types@15.7.12': resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} - '@types/react-dom@18.2.25': - resolution: {integrity: sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==} + '@types/react-dom@18.3.0': + resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} - '@types/react@18.2.79': - resolution: {integrity: sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==} + '@types/react@18.3.1': + resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==} '@types/require-from-string@1.2.3': resolution: {integrity: sha512-kxLU5xvefySGpp1Z7VCt4m5AhQJUZ8HjW8ADdeS7GieqFPHLAde007fd9bxeXEsFXyaA0LeWIoQXyXP17mGpIg==} @@ -1894,8 +1909,8 @@ packages: '@types/yargs@17.0.32': resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} - '@typescript-eslint/eslint-plugin@7.7.1': - resolution: {integrity: sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==} + '@typescript-eslint/eslint-plugin@7.8.0': + resolution: {integrity: sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -1905,8 +1920,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.7.1': - resolution: {integrity: sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==} + '@typescript-eslint/parser@7.8.0': + resolution: {integrity: sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1923,12 +1938,12 @@ packages: resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@7.7.1': - resolution: {integrity: sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==} + '@typescript-eslint/scope-manager@7.8.0': + resolution: {integrity: sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/type-utils@7.7.1': - resolution: {integrity: sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==} + '@typescript-eslint/type-utils@7.8.0': + resolution: {integrity: sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1945,8 +1960,8 @@ packages: resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@7.7.1': - resolution: {integrity: sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==} + '@typescript-eslint/types@7.8.0': + resolution: {integrity: sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript-eslint/typescript-estree@5.62.0': @@ -1967,8 +1982,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@7.7.1': - resolution: {integrity: sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==} + '@typescript-eslint/typescript-estree@7.8.0': + resolution: {integrity: sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -1988,8 +2003,8 @@ packages: peerDependencies: eslint: ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@7.7.1': - resolution: {integrity: sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==} + '@typescript-eslint/utils@7.8.0': + resolution: {integrity: sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -2002,8 +2017,8 @@ packages: resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@7.7.1': - resolution: {integrity: sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==} + '@typescript-eslint/visitor-keys@7.8.0': + resolution: {integrity: sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==} engines: {node: ^18.18.0 || >=20.0.0} '@webassemblyjs/ast@1.12.1': @@ -2137,8 +2152,8 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.13.0: + resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} @@ -2350,8 +2365,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001612: - resolution: {integrity: sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==} + caniuse-lite@1.0.30001615: + resolution: {integrity: sha512-1IpazM5G3r38meiae0bHRnPhz+CBQ3ZLqbQMtrg+AsTPKAXgW38JNsXkyZ+v8waCsDmPq87lmfun5Q2AGysNEQ==} chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} @@ -2384,8 +2399,8 @@ packages: cipher-base@1.0.4: resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} - cjs-module-lexer@1.2.3: - resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + cjs-module-lexer@1.3.1: + resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==} class-transformer@0.5.1: resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} @@ -2634,8 +2649,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.4.748: - resolution: {integrity: sha512-VWqjOlPZn70UZ8FTKUOkUvBLeTQ0xpty66qV0yJcAGY2/CthI4xyW9aEozRVtuwv3Kpf5xTesmJUcPwuJmgP4A==} + electron-to-chromium@1.4.754: + resolution: {integrity: sha512-7Kr5jUdns5rL/M9wFFmMZAgFDuL2YOnanFH4OI4iFzUqyh3XOL7nAGbSlSMZdzKMIyyTpNSbqZsWG9odwLeKvA==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -2661,8 +2676,8 @@ packages: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} engines: {node: '>=8.6'} - envinfo@7.12.0: - resolution: {integrity: sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==} + envinfo@7.13.0: + resolution: {integrity: sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==} engines: {node: '>=4'} hasBin: true @@ -2681,8 +2696,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.5.0: - resolution: {integrity: sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==} + es-module-lexer@1.5.2: + resolution: {integrity: sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA==} es-object-atoms@1.0.0: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} @@ -2761,8 +2776,8 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-jest@28.2.0: - resolution: {integrity: sha512-yRDti/a+f+SMSmNTiT9/M/MzXGkitl8CfzUxnpoQcTyfq8gUrXMriVcWU36W1X6BZSUoyUCJrDAWWUA2N4hE5g==} + eslint-plugin-jest@28.3.0: + resolution: {integrity: sha512-5LjCSSno8E+IUCOX4hJiIb/upPIgpkaDEcaN/40gOcw26t/5UTLHFc4JdxKjOOvGTh0XdCu+fNr0fpOVNvcxMA==} engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} peerDependencies: '@typescript-eslint/eslint-plugin': ^6.0.0 || ^7.0.0 @@ -2978,8 +2993,8 @@ packages: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} - fs-monkey@1.0.5: - resolution: {integrity: sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==} + fs-monkey@1.0.6: + resolution: {integrity: sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==} fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -3054,12 +3069,12 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@15.0.0: - resolution: {integrity: sha512-m/C/yR4mjO6pXDTm9/R/SpYTAIyaUB4EOzcaaMEl7mds7Mshct9GfejiJNQGjHHbdMPey13Kpu4TMbYi9ex1pw==} + globals@15.1.0: + resolution: {integrity: sha512-926gJqg+4mkxwYKiFvoomM4J0kWESfk3qfTvRL2/oc/tK/eTDBbrfcKnSa2KtfdxB5onoL7D3A3qIHQFpd4+UA==} engines: {node: '>=18'} - globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} globby@10.0.2: @@ -3129,6 +3144,10 @@ packages: engines: {node: '>=18'} hasBin: true + hyperdyperid@1.2.0: + resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} + engines: {node: '>=10.18'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -3591,8 +3610,8 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lru-cache@10.2.0: - resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} engines: {node: 14 || >=16.14} lru-cache@5.1.1: @@ -3619,8 +3638,8 @@ packages: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} - memfs@4.8.2: - resolution: {integrity: sha512-j4WKth315edViMBGkHW6NTF0QBjsTrcRDmYNcGsPq+ozMEyCCCIlX2d2mJ5wuh6iHvJ3FevUrr48v58YRqVdYg==} + memfs@4.9.2: + resolution: {integrity: sha512-f16coDZlTG1jskq3mxarwB+fGRrd0uXWt+o1WIhRfOwbXQZqUDsTVxQBFK9JjRQHblg8eAG2JSbprDXKjc7ijQ==} engines: {node: '>= 4.0.0'} merge-stream@2.0.0: @@ -3725,8 +3744,8 @@ packages: resolution: {integrity: sha512-nxJfz0ZmW+DKSr8evmVVm6t1XcLn9WHR5I8kiE2BFNkLVwC+nx+MimjJ53opfHOepMqQiGJAdstZ5Ks630bJgg==} hasBin: true - nx@18.3.3: - resolution: {integrity: sha512-GqC5ANfTWV6SFbgquZwuRMI2Z2nO0c0Yx4JzM3x32aJOgXsmRml3WcV0a5648bIXSen34gylHYl2EHaxVWkzNQ==} + nx@18.3.4: + resolution: {integrity: sha512-7rOHRyxpnZGJ3pHnwmpoAMHt9hNuwibWhOhPBJDhJVcbQJtGfwcWWyV/iSEnVXwKZ2lfHVE3TwE+gXFdT/GFiw==} hasBin: true peerDependencies: '@swc-node/register': ^1.8.0 @@ -3771,8 +3790,8 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} ora@5.3.0: @@ -3909,16 +3928,16 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - react-dom@18.2.0: - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: - react: ^18.2.0 + react: ^18.3.1 - react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} readable-stream@3.6.2: @@ -4026,8 +4045,8 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} - scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} schema-utils@3.3.0: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} @@ -4097,6 +4116,12 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + sonic-forest@1.0.2: + resolution: {integrity: sha512-2rICdwIJi5kVlehMUVtJeHn3ohh5YZV4pDv0P0c1M11cRz/gXNViItpM94HQwfvnXuzybpqK0LZJgTa3lEwtAw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + source-map-support@0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} @@ -4231,8 +4256,8 @@ packages: uglify-js: optional: true - terser@5.30.4: - resolution: {integrity: sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==} + terser@5.31.0: + resolution: {integrity: sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==} engines: {node: '>=10'} hasBin: true @@ -4243,6 +4268,12 @@ packages: text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + thingies@1.21.0: + resolution: {integrity: sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==} + engines: {node: '>=10.18'} + peerDependencies: + tslib: ^2 + thread-loader@4.0.2: resolution: {integrity: sha512-UOk/KBydsQjh4Ja5kocxDUzhv11KYptHN/h8gdSwo6/MBkYrWqQua6K2qwlpXnCXS9c/uLs8F/JF8rpveF0+fA==} engines: {node: '>= 16.10.0'} @@ -4267,6 +4298,12 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tree-dump@1.0.1: + resolution: {integrity: sha512-WCkcRBVPSlHHq1dc/px9iOfqklvzCbdRwvlNfxGZsrHqf6aZttfPrd7DJTt6oR10dwUfpFFQeVTkPbBIZxX/YA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -4352,8 +4389,8 @@ packages: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} - typescript-eslint@7.7.1: - resolution: {integrity: sha512-ykEBfa3xx3odjZy6GRED4SCPrjo0rgHwstLlEgLX4EMEuv7QeIDSmfV+S6Kk+XkbsYn4BDEcPvsci1X26lRpMQ==} + typescript-eslint@7.8.0: + resolution: {integrity: sha512-sheFG+/D8N/L7gC3WT0Q8sB97Nm573Yfr+vZFzl/4nBdYcmviBPtwGSX9TJ7wpVg28ocerKVOt+k2eGmHzcgVA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -4397,8 +4434,8 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - update-browserslist-db@1.0.13: - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + update-browserslist-db@1.0.14: + resolution: {integrity: sha512-JixKH8GR2pWYshIPUg/NujK3JO7JiqEEUiNArE86NQyrgUuZeTlZQN3xuS/yiV5Kb48ev9K6RqNkaJjXsdg7Jw==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -4490,6 +4527,10 @@ packages: wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + wrap-ansi@5.1.0: resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} engines: {node: '>=6'} @@ -4550,8 +4591,6 @@ packages: snapshots: - '@aashutoshrathi/word-wrap@1.2.6': {} - '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -4559,23 +4598,23 @@ snapshots: '@babel/code-frame@7.24.2': dependencies: - '@babel/highlight': 7.24.2 + '@babel/highlight': 7.24.5 picocolors: 1.0.0 '@babel/compat-data@7.24.4': {} - '@babel/core@7.24.4': + '@babel/core@7.24.5': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.24.2 - '@babel/generator': 7.24.4 + '@babel/generator': 7.24.5 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helpers': 7.24.4 - '@babel/parser': 7.24.4 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helpers': 7.24.5 + '@babel/parser': 7.24.5 '@babel/template': 7.24.0 - '@babel/traverse': 7.24.1 - '@babel/types': 7.24.0 + '@babel/traverse': 7.24.5 + '@babel/types': 7.24.5 convert-source-map: 2.0.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -4584,20 +4623,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.24.4': + '@babel/generator@7.24.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 '@babel/helper-annotate-as-pure@7.22.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@babel/helper-compilation-targets@7.23.6': dependencies: @@ -4607,31 +4646,31 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.24.4(@babel/core@7.24.4)': + '@babel/helper-create-class-features-plugin@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 - '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.24.5 '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.4) + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.5) '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-split-export-declaration': 7.24.5 semver: 6.3.1 - '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.4)': + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-annotate-as-pure': 7.22.5 regexpu-core: 5.3.2 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.4)': + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.5 debug: 4.3.4 lodash.debounce: 4.0.8 resolve: 1.22.8 @@ -4643,683 +4682,683 @@ snapshots: '@babel/helper-function-name@7.23.0': dependencies: '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@babel/helper-hoist-variables@7.22.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 - '@babel/helper-member-expression-to-functions@7.23.0': + '@babel/helper-member-expression-to-functions@7.24.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@babel/helper-module-imports@7.24.3': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 - '@babel/helper-module-transforms@7.23.3(@babel/core@7.24.4)': + '@babel/helper-module-transforms@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.24.3 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-simple-access': 7.24.5 + '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-validator-identifier': 7.24.5 '@babel/helper-optimise-call-expression@7.22.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 - '@babel/helper-plugin-utils@7.24.0': {} + '@babel/helper-plugin-utils@7.24.5': {} - '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.4)': + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-wrap-function': 7.24.5 - '@babel/helper-replace-supers@7.24.1(@babel/core@7.24.4)': + '@babel/helper-replace-supers@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.24.5 '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-simple-access@7.22.5': + '@babel/helper-simple-access@7.24.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@babel/helper-skip-transparent-expression-wrappers@7.22.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 - '@babel/helper-split-export-declaration@7.22.6': + '@babel/helper-split-export-declaration@7.24.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@babel/helper-string-parser@7.24.1': {} - '@babel/helper-validator-identifier@7.22.20': {} + '@babel/helper-validator-identifier@7.24.5': {} '@babel/helper-validator-option@7.23.5': {} - '@babel/helper-wrap-function@7.22.20': + '@babel/helper-wrap-function@7.24.5': dependencies: '@babel/helper-function-name': 7.23.0 '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 - '@babel/helpers@7.24.4': + '@babel/helpers@7.24.5': dependencies: '@babel/template': 7.24.0 - '@babel/traverse': 7.24.1 - '@babel/types': 7.24.0 + '@babel/traverse': 7.24.5 + '@babel/types': 7.24.5 transitivePeerDependencies: - supports-color - '@babel/highlight@7.24.2': + '@babel/highlight@7.24.5': dependencies: - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.5 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.0 - '@babel/parser@7.24.4': + '@babel/parser@7.24.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.4(@babel/core@7.24.4)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.24.1(@babel/core@7.24.4) + '@babel/plugin-transform-optional-chaining': 7.24.5(@babel/core@7.24.5) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-proposal-decorators@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-proposal-decorators@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-class-features-plugin': 7.24.4(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-decorators': 7.24.1(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-decorators': 7.24.1(@babel/core@7.24.5) - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.4)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.4)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.4)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.4)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.4)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-decorators@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-syntax-decorators@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.4)': + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.4)': + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-import-assertions@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-syntax-import-assertions@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-import-attributes@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-syntax-import-attributes@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.4)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.4)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.4)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.4)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.4)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.4)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.4)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.4)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.4)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.4)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.4)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-arrow-functions@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-arrow-functions@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-async-generator-functions@7.24.3(@babel/core@7.24.4)': + '@babel/plugin-transform-async-generator-functions@7.24.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.4) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.4) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.5) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.5) - '@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-module-imports': 7.24.3 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.4) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.5) - '@babel/plugin-transform-block-scoped-functions@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-block-scoped-functions@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-block-scoping@7.24.4(@babel/core@7.24.4)': + '@babel/plugin-transform-block-scoping@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-class-properties@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-class-properties@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-class-features-plugin': 7.24.4(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-class-static-block@7.24.4(@babel/core@7.24.4)': + '@babel/plugin-transform-class-static-block@7.24.4(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-class-features-plugin': 7.24.4(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.5) - '@babel/plugin-transform-classes@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-classes@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.4) - '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.5) + '@babel/helper-split-export-declaration': 7.24.5 globals: 11.12.0 - '@babel/plugin-transform-computed-properties@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-computed-properties@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 '@babel/template': 7.24.0 - '@babel/plugin-transform-destructuring@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-destructuring@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-dotall-regex@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-dotall-regex@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-duplicate-keys@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-duplicate-keys@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-dynamic-import@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-dynamic-import@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.5) - '@babel/plugin-transform-exponentiation-operator@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-exponentiation-operator@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-export-namespace-from@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-export-namespace-from@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.5) - '@babel/plugin-transform-for-of@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-for-of@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-function-name@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-function-name@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-json-strings@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-json-strings@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.5) - '@babel/plugin-transform-literals@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-literals@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-logical-assignment-operators@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-logical-assignment-operators@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.5) - '@babel/plugin-transform-member-expression-literals@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-member-expression-literals@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-modules-amd@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-modules-amd@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-simple-access': 7.22.5 + '@babel/core': 7.24.5 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-simple-access': 7.24.5 - '@babel/plugin-transform-modules-systemjs@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-modules-systemjs@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-validator-identifier': 7.24.5 - '@babel/plugin-transform-modules-umd@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-modules-umd@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-new-target@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-new-target@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-nullish-coalescing-operator@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-nullish-coalescing-operator@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.5) - '@babel/plugin-transform-numeric-separator@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-numeric-separator@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.5) - '@babel/plugin-transform-object-rest-spread@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-object-rest-spread@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.4) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-transform-parameters': 7.24.5(@babel/core@7.24.5) - '@babel/plugin-transform-object-super@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-object-super@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.5) - '@babel/plugin-transform-optional-catch-binding@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-optional-catch-binding@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.5) - '@babel/plugin-transform-optional-chaining@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-optional-chaining@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.4) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.5) - '@babel/plugin-transform-parameters@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-parameters@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-private-methods@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-private-methods@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-class-features-plugin': 7.24.4(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-private-property-in-object@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-private-property-in-object@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.4(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.4) + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.5) - '@babel/plugin-transform-property-literals@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-property-literals@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-regenerator@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-regenerator@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-runtime@7.24.3(@babel/core@7.24.4)': + '@babel/plugin-transform-runtime@7.24.3(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-module-imports': 7.24.3 - '@babel/helper-plugin-utils': 7.24.0 - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.4) - babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.4) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.4) + '@babel/helper-plugin-utils': 7.24.5 + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.5) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.5) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.5) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-shorthand-properties@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-spread@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-spread@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-sticky-regex@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-sticky-regex@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-template-literals@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-template-literals@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-typeof-symbol@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-typeof-symbol@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-typescript@7.24.4(@babel/core@7.24.4)': + '@babel/plugin-transform-typescript@7.24.5(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.4(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.4) + '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.5) - '@babel/plugin-transform-unicode-escapes@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-unicode-escapes@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-unicode-property-regex@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-unicode-property-regex@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-unicode-regex@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-unicode-regex@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-transform-unicode-sets-regex@7.24.1(@babel/core@7.24.4)': + '@babel/plugin-transform-unicode-sets-regex@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.24.5 - '@babel/preset-env@7.24.4(@babel/core@7.24.4)': + '@babel/preset-env@7.24.5(@babel/core@7.24.5)': dependencies: '@babel/compat-data': 7.24.4 - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.4(@babel/core@7.24.4) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.4) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.4) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.4) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.4) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-import-assertions': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-syntax-import-attributes': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.4) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.4) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.4) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.4) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.4) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.4) - '@babel/plugin-transform-arrow-functions': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-async-generator-functions': 7.24.3(@babel/core@7.24.4) - '@babel/plugin-transform-async-to-generator': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-block-scoped-functions': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-block-scoping': 7.24.4(@babel/core@7.24.4) - '@babel/plugin-transform-class-properties': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-class-static-block': 7.24.4(@babel/core@7.24.4) - '@babel/plugin-transform-classes': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-computed-properties': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-destructuring': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-dotall-regex': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-duplicate-keys': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-dynamic-import': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-exponentiation-operator': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-export-namespace-from': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-for-of': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-function-name': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-json-strings': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-literals': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-logical-assignment-operators': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-member-expression-literals': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-modules-amd': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-modules-systemjs': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-modules-umd': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.4) - '@babel/plugin-transform-new-target': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-nullish-coalescing-operator': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-numeric-separator': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-object-rest-spread': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-object-super': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-optional-catch-binding': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-optional-chaining': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-private-methods': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-private-property-in-object': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-property-literals': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-regenerator': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-reserved-words': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-shorthand-properties': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-spread': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-sticky-regex': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-template-literals': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-typeof-symbol': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-unicode-escapes': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-unicode-property-regex': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-unicode-regex': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-unicode-sets-regex': 7.24.1(@babel/core@7.24.4) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.4) - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.4) - babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.4) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.4) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.5) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.5) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.5) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-import-assertions': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-syntax-import-attributes': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.5) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.5) + '@babel/plugin-transform-arrow-functions': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-async-generator-functions': 7.24.3(@babel/core@7.24.5) + '@babel/plugin-transform-async-to-generator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-block-scoped-functions': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-block-scoping': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-class-properties': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-class-static-block': 7.24.4(@babel/core@7.24.5) + '@babel/plugin-transform-classes': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-computed-properties': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-destructuring': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-dotall-regex': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-duplicate-keys': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-dynamic-import': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-exponentiation-operator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-export-namespace-from': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-for-of': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-function-name': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-json-strings': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-literals': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-logical-assignment-operators': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-member-expression-literals': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-modules-amd': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-modules-systemjs': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-modules-umd': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.5) + '@babel/plugin-transform-new-target': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-numeric-separator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-object-rest-spread': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-object-super': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-optional-catch-binding': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-optional-chaining': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-parameters': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-private-methods': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-private-property-in-object': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-property-literals': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-regenerator': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-reserved-words': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-shorthand-properties': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-spread': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-sticky-regex': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-template-literals': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-typeof-symbol': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-unicode-escapes': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-unicode-property-regex': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-unicode-regex': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-unicode-sets-regex': 7.24.1(@babel/core@7.24.5) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.5) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.5) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.5) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.5) core-js-compat: 3.37.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.4)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/types': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/types': 7.24.5 esutils: 2.0.3 - '@babel/preset-typescript@7.24.1(@babel/core@7.24.4)': + '@babel/preset-typescript@7.24.1(@babel/core@7.24.5)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-typescript': 7.24.4(@babel/core@7.24.4) + '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-typescript': 7.24.5(@babel/core@7.24.5) '@babel/regjsgen@0.8.0': {} - '@babel/runtime@7.24.4': + '@babel/runtime@7.24.5': dependencies: regenerator-runtime: 0.14.1 '@babel/template@7.24.0': dependencies: '@babel/code-frame': 7.24.2 - '@babel/parser': 7.24.4 - '@babel/types': 7.24.0 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 - '@babel/traverse@7.24.1': + '@babel/traverse@7.24.5': dependencies: '@babel/code-frame': 7.24.2 - '@babel/generator': 7.24.4 + '@babel/generator': 7.24.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.24.4 - '@babel/types': 7.24.0 + '@babel/helper-split-export-declaration': 7.24.5 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/types@7.24.0': + '@babel/types@7.24.5': dependencies: '@babel/helper-string-parser': 7.24.1 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.5 to-fast-properties: 2.0.0 '@bcoe/v8-coverage@0.2.3': {} @@ -5400,27 +5439,27 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5))': + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -5449,7 +5488,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -5467,7 +5506,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.12.7 + '@types/node': 20.12.8 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -5489,7 +5528,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 20.12.7 + '@types/node': 20.12.8 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -5536,7 +5575,7 @@ snapshots: '@jest/transform@29.7.0': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 babel-plugin-istanbul: 6.1.1 @@ -5559,7 +5598,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.12.7 + '@types/node': 20.12.8 '@types/yargs': 17.0.32 chalk: 4.1.2 @@ -5590,6 +5629,22 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 + '@jsonjoy.com/base64@1.1.1(tslib@2.6.2)': + dependencies: + tslib: 2.6.2 + + '@jsonjoy.com/json-pack@1.0.3(tslib@2.6.2)': + dependencies: + '@jsonjoy.com/base64': 1.1.1(tslib@2.6.2) + '@jsonjoy.com/util': 1.1.2(tslib@2.6.2) + hyperdyperid: 1.2.0 + thingies: 1.21.0(tslib@2.6.2) + tslib: 2.6.2 + + '@jsonjoy.com/util@1.1.2(tslib@2.6.2)': + dependencies: + tslib: 2.6.2 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -5602,15 +5657,15 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@nrwl/devkit@18.3.3(nx@18.3.3(@swc/core@1.5.0))': + '@nrwl/devkit@18.3.4(nx@18.3.4(@swc/core@1.5.0))': dependencies: - '@nx/devkit': 18.3.3(nx@18.3.3(@swc/core@1.5.0)) + '@nx/devkit': 18.3.4(nx@18.3.4(@swc/core@1.5.0)) transitivePeerDependencies: - nx - '@nrwl/eslint-plugin-nx@18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5)': + '@nrwl/eslint-plugin-nx@18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5)': dependencies: - '@nx/eslint-plugin': 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + '@nx/eslint-plugin': 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -5626,9 +5681,9 @@ snapshots: - typescript - verdaccio - '@nrwl/js@18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5)': + '@nrwl/js@18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5)': dependencies: - '@nx/js': 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) + '@nx/js': 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -5647,43 +5702,43 @@ snapshots: transitivePeerDependencies: - debug - '@nrwl/tao@18.3.3(@swc/core@1.5.0)': + '@nrwl/tao@18.3.4(@swc/core@1.5.0)': dependencies: - nx: 18.3.3(@swc/core@1.5.0) + nx: 18.3.4(@swc/core@1.5.0) tslib: 2.6.2 transitivePeerDependencies: - '@swc-node/register' - '@swc/core' - debug - '@nrwl/workspace@18.3.3(@swc/core@1.5.0)': + '@nrwl/workspace@18.3.4(@swc/core@1.5.0)': dependencies: - '@nx/workspace': 18.3.3(@swc/core@1.5.0) + '@nx/workspace': 18.3.4(@swc/core@1.5.0) transitivePeerDependencies: - '@swc-node/register' - '@swc/core' - debug - '@nx/devkit@18.3.3(nx@18.3.3(@swc/core@1.5.0))': + '@nx/devkit@18.3.4(nx@18.3.4(@swc/core@1.5.0))': dependencies: - '@nrwl/devkit': 18.3.3(nx@18.3.3(@swc/core@1.5.0)) + '@nrwl/devkit': 18.3.4(nx@18.3.4(@swc/core@1.5.0)) ejs: 3.1.10 enquirer: 2.3.6 ignore: 5.3.1 - nx: 18.3.3(@swc/core@1.5.0) + nx: 18.3.4(@swc/core@1.5.0) semver: 7.6.0 tmp: 0.2.3 tslib: 2.6.2 yargs-parser: 21.1.1 - '@nx/eslint-plugin@18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5)': + '@nx/eslint-plugin@18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5)': dependencies: - '@nrwl/eslint-plugin-nx': 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) - '@nx/devkit': 18.3.3(nx@18.3.3(@swc/core@1.5.0)) - '@nx/js': 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) - '@typescript-eslint/parser': 7.7.1(eslint@9.1.1)(typescript@5.4.5) - '@typescript-eslint/type-utils': 7.7.1(eslint@9.1.1)(typescript@5.4.5) - '@typescript-eslint/utils': 7.7.1(eslint@9.1.1)(typescript@5.4.5) + '@nrwl/eslint-plugin-nx': 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) + '@nx/devkit': 18.3.4(nx@18.3.4(@swc/core@1.5.0)) + '@nx/js': 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) + '@typescript-eslint/parser': 7.8.0(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/type-utils': 7.8.0(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/utils': 7.8.0(eslint@9.1.1)(typescript@5.4.5) chalk: 4.1.2 confusing-browser-globals: 1.0.11 jsonc-eslint-parser: 2.4.0 @@ -5704,22 +5759,22 @@ snapshots: - typescript - verdaccio - '@nx/js@18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5)': - dependencies: - '@babel/core': 7.24.4 - '@babel/plugin-proposal-decorators': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-class-properties': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-transform-runtime': 7.24.3(@babel/core@7.24.4) - '@babel/preset-env': 7.24.4(@babel/core@7.24.4) - '@babel/preset-typescript': 7.24.1(@babel/core@7.24.4) - '@babel/runtime': 7.24.4 - '@nrwl/js': 18.3.3(@babel/traverse@7.24.1)(@swc/core@1.5.0)(@types/node@20.12.7)(nx@18.3.3(@swc/core@1.5.0))(typescript@5.4.5) - '@nx/devkit': 18.3.3(nx@18.3.3(@swc/core@1.5.0)) - '@nx/workspace': 18.3.3(@swc/core@1.5.0) + '@nx/js@18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/plugin-proposal-decorators': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-class-properties': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-transform-runtime': 7.24.3(@babel/core@7.24.5) + '@babel/preset-env': 7.24.5(@babel/core@7.24.5) + '@babel/preset-typescript': 7.24.1(@babel/core@7.24.5) + '@babel/runtime': 7.24.5 + '@nrwl/js': 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) + '@nx/devkit': 18.3.4(nx@18.3.4(@swc/core@1.5.0)) + '@nx/workspace': 18.3.4(@swc/core@1.5.0) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.4.5) - babel-plugin-const-enum: 1.2.0(@babel/core@7.24.4) + babel-plugin-const-enum: 1.2.0(@babel/core@7.24.5) babel-plugin-macros: 2.8.0 - babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.24.4)(@babel/traverse@7.24.1) + babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.24.5)(@babel/traverse@7.24.5) chalk: 4.1.2 columnify: 1.6.0 detect-port: 1.5.1 @@ -5733,7 +5788,7 @@ snapshots: ora: 5.3.0 semver: 7.6.0 source-map-support: 0.5.19 - ts-node: 10.9.1(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5) + ts-node: 10.9.1(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5) tsconfig-paths: 4.2.0 tslib: 2.6.2 transitivePeerDependencies: @@ -5747,43 +5802,43 @@ snapshots: - supports-color - typescript - '@nx/nx-darwin-arm64@18.3.3': + '@nx/nx-darwin-arm64@18.3.4': optional: true - '@nx/nx-darwin-x64@18.3.3': + '@nx/nx-darwin-x64@18.3.4': optional: true - '@nx/nx-freebsd-x64@18.3.3': + '@nx/nx-freebsd-x64@18.3.4': optional: true - '@nx/nx-linux-arm-gnueabihf@18.3.3': + '@nx/nx-linux-arm-gnueabihf@18.3.4': optional: true - '@nx/nx-linux-arm64-gnu@18.3.3': + '@nx/nx-linux-arm64-gnu@18.3.4': optional: true - '@nx/nx-linux-arm64-musl@18.3.3': + '@nx/nx-linux-arm64-musl@18.3.4': optional: true - '@nx/nx-linux-x64-gnu@18.3.3': + '@nx/nx-linux-x64-gnu@18.3.4': optional: true - '@nx/nx-linux-x64-musl@18.3.3': + '@nx/nx-linux-x64-musl@18.3.4': optional: true - '@nx/nx-win32-arm64-msvc@18.3.3': + '@nx/nx-win32-arm64-msvc@18.3.4': optional: true - '@nx/nx-win32-x64-msvc@18.3.3': + '@nx/nx-win32-x64-msvc@18.3.4': optional: true - '@nx/workspace@18.3.3(@swc/core@1.5.0)': + '@nx/workspace@18.3.4(@swc/core@1.5.0)': dependencies: - '@nrwl/workspace': 18.3.3(@swc/core@1.5.0) - '@nx/devkit': 18.3.3(nx@18.3.3(@swc/core@1.5.0)) + '@nrwl/workspace': 18.3.4(@swc/core@1.5.0) + '@nx/devkit': 18.3.4(nx@18.3.4(@swc/core@1.5.0)) chalk: 4.1.2 enquirer: 2.3.6 - nx: 18.3.3(@swc/core@1.5.0) + nx: 18.3.4(@swc/core@1.5.0) tslib: 2.6.2 yargs-parser: 21.1.1 transitivePeerDependencies: @@ -5880,24 +5935,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.24.4 - '@babel/types': 7.24.0 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.5 '@types/babel__generator@7.6.8': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.24.4 - '@babel/types': 7.24.0 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 '@types/babel__traverse@7.20.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@types/eslint-scope@3.7.7': dependencies: @@ -5914,16 +5969,16 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.12.7 + '@types/node': 20.12.8 '@types/glob@8.1.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.12.7 + '@types/node': 20.12.8 '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.12.8 '@types/istanbul-lib-coverage@2.0.6': {} @@ -5950,7 +6005,7 @@ snapshots: '@types/minimist@1.2.5': {} - '@types/node@20.12.7': + '@types/node@20.12.8': dependencies: undici-types: 5.26.5 @@ -5958,11 +6013,11 @@ snapshots: '@types/prop-types@15.7.12': {} - '@types/react-dom@18.2.25': + '@types/react-dom@18.3.0': dependencies: - '@types/react': 18.2.79 + '@types/react': 18.3.1 - '@types/react@18.2.79': + '@types/react@18.3.1': dependencies: '@types/prop-types': 15.7.12 csstype: 3.1.3 @@ -5977,7 +6032,7 @@ snapshots: '@types/webpack@5.28.5(@swc/core@1.5.0)(webpack-cli@5.1.4(webpack@5.91.0))': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.12.8 tapable: 2.2.1 webpack: 5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4) transitivePeerDependencies: @@ -5992,14 +6047,14 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.7.1(eslint@9.1.1)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.7.1 - '@typescript-eslint/type-utils': 7.7.1(eslint@9.1.1)(typescript@5.4.5) - '@typescript-eslint/utils': 7.7.1(eslint@9.1.1)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.7.1 + '@typescript-eslint/parser': 7.8.0(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.8.0 + '@typescript-eslint/type-utils': 7.8.0(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/utils': 7.8.0(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.8.0 debug: 4.3.4 eslint: 9.1.1 graphemer: 1.4.0 @@ -6012,12 +6067,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5)': + '@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5)': dependencies: - '@typescript-eslint/scope-manager': 7.7.1 - '@typescript-eslint/types': 7.7.1 - '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.7.1 + '@typescript-eslint/scope-manager': 7.8.0 + '@typescript-eslint/types': 7.8.0 + '@typescript-eslint/typescript-estree': 7.8.0(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.8.0 debug: 4.3.4 eslint: 9.1.1 optionalDependencies: @@ -6035,15 +6090,15 @@ snapshots: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - '@typescript-eslint/scope-manager@7.7.1': + '@typescript-eslint/scope-manager@7.8.0': dependencies: - '@typescript-eslint/types': 7.7.1 - '@typescript-eslint/visitor-keys': 7.7.1 + '@typescript-eslint/types': 7.8.0 + '@typescript-eslint/visitor-keys': 7.8.0 - '@typescript-eslint/type-utils@7.7.1(eslint@9.1.1)(typescript@5.4.5)': + '@typescript-eslint/type-utils@7.8.0(eslint@9.1.1)(typescript@5.4.5)': dependencies: - '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) - '@typescript-eslint/utils': 7.7.1(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.8.0(typescript@5.4.5) + '@typescript-eslint/utils': 7.8.0(eslint@9.1.1)(typescript@5.4.5) debug: 4.3.4 eslint: 9.1.1 ts-api-utils: 1.3.0(typescript@5.4.5) @@ -6056,7 +6111,7 @@ snapshots: '@typescript-eslint/types@6.21.0': {} - '@typescript-eslint/types@7.7.1': {} + '@typescript-eslint/types@7.8.0': {} '@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.5)': dependencies: @@ -6087,10 +6142,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.7.1(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.8.0(typescript@5.4.5)': dependencies: - '@typescript-eslint/types': 7.7.1 - '@typescript-eslint/visitor-keys': 7.7.1 + '@typescript-eslint/types': 7.8.0 + '@typescript-eslint/visitor-keys': 7.8.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -6131,14 +6186,14 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@7.7.1(eslint@9.1.1)(typescript@5.4.5)': + '@typescript-eslint/utils@7.8.0(eslint@9.1.1)(typescript@5.4.5)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.1.1) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 7.7.1 - '@typescript-eslint/types': 7.7.1 - '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.8.0 + '@typescript-eslint/types': 7.8.0 + '@typescript-eslint/typescript-estree': 7.8.0(typescript@5.4.5) eslint: 9.1.1 semver: 7.6.0 transitivePeerDependencies: @@ -6155,9 +6210,9 @@ snapshots: '@typescript-eslint/types': 6.21.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.7.1': + '@typescript-eslint/visitor-keys@7.8.0': dependencies: - '@typescript-eslint/types': 7.7.1 + '@typescript-eslint/types': 7.8.0 eslint-visitor-keys: 3.4.3 '@webassemblyjs/ast@1.12.1': @@ -6280,17 +6335,17 @@ snapshots: address@1.2.2: {} - ajv-formats@2.1.1(ajv@8.12.0): + ajv-formats@2.1.1(ajv@8.13.0): optionalDependencies: - ajv: 8.12.0 + ajv: 8.13.0 ajv-keywords@3.5.2(ajv@6.12.6): dependencies: ajv: 6.12.6 - ajv-keywords@5.1.0(ajv@8.12.0): + ajv-keywords@5.1.0(ajv@8.13.0): dependencies: - ajv: 8.12.0 + ajv: 8.13.0 fast-deep-equal: 3.1.3 ajv@6.12.6: @@ -6300,7 +6355,7 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.12.0: + ajv@8.13.0: dependencies: fast-deep-equal: 3.1.3 json-schema-traverse: 1.0.0 @@ -6418,31 +6473,31 @@ snapshots: transitivePeerDependencies: - debug - babel-jest@29.7.0(@babel/core@7.24.4): + babel-jest@29.7.0(@babel/core@7.24.5): dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.24.4) + babel-preset-jest: 29.6.3(@babel/core@7.24.5) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - babel-plugin-const-enum@1.2.0(@babel/core@7.24.4): + babel-plugin-const-enum@1.2.0(@babel/core@7.24.5): dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.4) - '@babel/traverse': 7.24.1 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.5) + '@babel/traverse': 7.24.5 transitivePeerDependencies: - supports-color babel-plugin-istanbul@6.1.1: dependencies: - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.5 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 5.2.1 @@ -6453,75 +6508,75 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/types': 7.24.5 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.5 babel-plugin-macros@2.8.0: dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 cosmiconfig: 6.0.0 resolve: 1.22.8 babel-plugin-macros@3.1.0: dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 cosmiconfig: 7.1.0 resolve: 1.22.8 optional: true - babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.4): + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.5): dependencies: '@babel/compat-data': 7.24.4 - '@babel/core': 7.24.4 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.5) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.4): + babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.5): dependencies: - '@babel/core': 7.24.4 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.5) core-js-compat: 3.37.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.4): + babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.5): dependencies: - '@babel/core': 7.24.4 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.4) + '@babel/core': 7.24.5 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.5) transitivePeerDependencies: - supports-color - babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.24.4)(@babel/traverse@7.24.1): + babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.24.5)(@babel/traverse@7.24.5): dependencies: - '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 optionalDependencies: - '@babel/traverse': 7.24.1 - - babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.4): - dependencies: - '@babel/core': 7.24.4 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.4) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.4) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.4) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.4) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.4) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.4) - - babel-preset-jest@29.6.3(@babel/core@7.24.4): - dependencies: - '@babel/core': 7.24.4 + '@babel/traverse': 7.24.5 + + babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.5): + dependencies: + '@babel/core': 7.24.5 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.5) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.5) + + babel-preset-jest@29.6.3(@babel/core@7.24.5): + dependencies: + '@babel/core': 7.24.5 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.4) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.5) balanced-match@1.0.2: {} @@ -6550,10 +6605,10 @@ snapshots: browserslist@4.23.0: dependencies: - caniuse-lite: 1.0.30001612 - electron-to-chromium: 1.4.748 + caniuse-lite: 1.0.30001615 + electron-to-chromium: 1.4.754 node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.23.0) + update-browserslist-db: 1.0.14(browserslist@4.23.0) bser@2.1.1: dependencies: @@ -6584,7 +6639,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001612: {} + caniuse-lite@1.0.30001615: {} chalk@2.4.2: dependencies: @@ -6622,7 +6677,7 @@ snapshots: inherits: 2.0.4 safe-buffer: 5.2.1 - cjs-module-lexer@1.2.3: {} + cjs-module-lexer@1.3.1: {} class-transformer@0.5.1: {} @@ -6743,13 +6798,13 @@ snapshots: ripemd160: 2.0.2 sha.js: 2.4.11 - create-jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)): + create-jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -6792,7 +6847,7 @@ snapshots: date-fns@2.30.0: dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 debug@3.2.7: dependencies: @@ -6867,7 +6922,7 @@ snapshots: dependencies: jake: 10.8.7 - electron-to-chromium@1.4.748: {} + electron-to-chromium@1.4.754: {} emittery@0.13.1: {} @@ -6890,7 +6945,7 @@ snapshots: dependencies: ansi-colors: 4.1.3 - envinfo@7.12.0: {} + envinfo@7.13.0: {} error-ex@1.3.2: dependencies: @@ -6913,7 +6968,7 @@ snapshots: function.prototype.name: 1.1.6 get-intrinsic: 1.2.4 get-symbol-description: 1.0.2 - globalthis: 1.0.3 + globalthis: 1.0.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 has-proto: 1.0.3 @@ -6951,7 +7006,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.5.0: {} + es-module-lexer@1.5.2: {} es-object-atoms@1.0.0: dependencies: @@ -6985,9 +7040,9 @@ snapshots: dependencies: eslint: 9.1.1 - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)): dependencies: - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1) eslint-import-resolver-node@0.3.9: dependencies: @@ -6997,17 +7052,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@9.1.1): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@9.1.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.7.1(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/parser': 7.8.0(eslint@9.1.1)(typescript@5.4.5) eslint: 9.1.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -7017,7 +7072,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.1.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@9.1.1) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@9.1.1) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -7028,19 +7083,19 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.7.1(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/parser': 7.8.0(eslint@9.1.1)(typescript@5.4.5) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@28.2.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)))(typescript@5.4.5): + eslint-plugin-jest@28.3.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)))(typescript@5.4.5): dependencies: '@typescript-eslint/utils': 6.21.0(eslint@9.1.1)(typescript@5.4.5) eslint: 9.1.1 optionalDependencies: - '@typescript-eslint/eslint-plugin': 7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5) - jest: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + '@typescript-eslint/eslint-plugin': 7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5) + jest: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) transitivePeerDependencies: - supports-color - typescript @@ -7110,7 +7165,7 @@ snapshots: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: @@ -7316,7 +7371,7 @@ snapshots: dependencies: minipass: 3.3.6 - fs-monkey@1.0.5: {} + fs-monkey@1.0.6: {} fs.realpath@1.0.0: {} @@ -7389,11 +7444,12 @@ snapshots: globals@14.0.0: {} - globals@15.0.0: {} + globals@15.1.0: {} - globalthis@1.0.3: + globalthis@1.0.4: dependencies: define-properties: 1.2.1 + gopd: 1.0.1 globby@10.0.2: dependencies: @@ -7453,7 +7509,7 @@ snapshots: hosted-git-info@7.0.1: dependencies: - lru-cache: 10.2.0 + lru-cache: 10.2.2 html-escaper@2.0.2: {} @@ -7461,6 +7517,8 @@ snapshots: husky@9.0.11: {} + hyperdyperid@1.2.0: {} + ieee754@1.2.1: {} ignore@5.3.1: {} @@ -7601,8 +7659,8 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: - '@babel/core': 7.24.4 - '@babel/parser': 7.24.4 + '@babel/core': 7.24.5 + '@babel/parser': 7.24.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -7611,8 +7669,8 @@ snapshots: istanbul-lib-instrument@6.0.2: dependencies: - '@babel/core': 7.24.4 - '@babel/parser': 7.24.4 + '@babel/core': 7.24.5 + '@babel/parser': 7.24.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.6.0 @@ -7663,7 +7721,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3(babel-plugin-macros@3.1.0) @@ -7683,16 +7741,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)): + jest-cli@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + create-jest: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -7702,12 +7760,12 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)): dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.5 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.24.4) + babel-jest: 29.7.0(@babel/core@7.24.5) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -7727,8 +7785,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.12.7 - ts-node: 10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5) + '@types/node': 20.12.8 + ts-node: 10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -7757,7 +7815,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -7767,7 +7825,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.12.7 + '@types/node': 20.12.8 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -7806,7 +7864,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -7841,7 +7899,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -7869,9 +7927,9 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 chalk: 4.1.2 - cjs-module-lexer: 1.2.3 + cjs-module-lexer: 1.3.1 collect-v8-coverage: 1.0.2 glob: 7.2.3 graceful-fs: 4.2.11 @@ -7889,15 +7947,15 @@ snapshots: jest-snapshot@29.7.0: dependencies: - '@babel/core': 7.24.4 - '@babel/generator': 7.24.4 - '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.4) - '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.4) - '@babel/types': 7.24.0 + '@babel/core': 7.24.5 + '@babel/generator': 7.24.5 + '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.5) + '@babel/types': 7.24.5 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.4) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.5) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -7915,7 +7973,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -7934,7 +7992,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.12.8 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -7943,23 +8001,23 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 20.12.7 + '@types/node': 20.12.8 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 20.12.7 + '@types/node': 20.12.8 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)): + jest@29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.12.7)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5)) + jest-cli: 29.7.0(@types/node@20.12.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -8081,7 +8139,7 @@ snapshots: dependencies: js-tokens: 4.0.0 - lru-cache@10.2.0: {} + lru-cache@10.2.2: {} lru-cache@5.1.1: dependencies: @@ -8109,10 +8167,13 @@ snapshots: memfs@3.5.3: dependencies: - fs-monkey: 1.0.5 + fs-monkey: 1.0.6 - memfs@4.8.2: + memfs@4.9.2: dependencies: + '@jsonjoy.com/json-pack': 1.0.3(tslib@2.6.2) + '@jsonjoy.com/util': 1.1.2(tslib@2.6.2) + sonic-forest: 1.0.2(tslib@2.6.2) tslib: 2.6.2 merge-stream@2.0.0: {} @@ -8209,9 +8270,9 @@ snapshots: transitivePeerDependencies: - debug - nx@18.3.3(@swc/core@1.5.0): + nx@18.3.4(@swc/core@1.5.0): dependencies: - '@nrwl/tao': 18.3.3(@swc/core@1.5.0) + '@nrwl/tao': 18.3.4(@swc/core@1.5.0) '@yarnpkg/lockfile': 1.1.0 '@yarnpkg/parsers': 3.0.0-rc.46 '@zkochan/js-yaml': 0.0.6 @@ -8246,16 +8307,16 @@ snapshots: yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@nx/nx-darwin-arm64': 18.3.3 - '@nx/nx-darwin-x64': 18.3.3 - '@nx/nx-freebsd-x64': 18.3.3 - '@nx/nx-linux-arm-gnueabihf': 18.3.3 - '@nx/nx-linux-arm64-gnu': 18.3.3 - '@nx/nx-linux-arm64-musl': 18.3.3 - '@nx/nx-linux-x64-gnu': 18.3.3 - '@nx/nx-linux-x64-musl': 18.3.3 - '@nx/nx-win32-arm64-msvc': 18.3.3 - '@nx/nx-win32-x64-msvc': 18.3.3 + '@nx/nx-darwin-arm64': 18.3.4 + '@nx/nx-darwin-x64': 18.3.4 + '@nx/nx-freebsd-x64': 18.3.4 + '@nx/nx-linux-arm-gnueabihf': 18.3.4 + '@nx/nx-linux-arm64-gnu': 18.3.4 + '@nx/nx-linux-arm64-musl': 18.3.4 + '@nx/nx-linux-x64-gnu': 18.3.4 + '@nx/nx-linux-x64-musl': 18.3.4 + '@nx/nx-win32-arm64-msvc': 18.3.4 + '@nx/nx-win32-x64-msvc': 18.3.4 '@swc/core': 1.5.0 transitivePeerDependencies: - debug @@ -8304,14 +8365,14 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - optionator@0.9.3: + optionator@0.9.4: dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 + word-wrap: 1.2.5 ora@5.3.0: dependencies: @@ -8369,7 +8430,7 @@ snapshots: path-scurry@1.10.2: dependencies: - lru-cache: 10.2.0 + lru-cache: 10.2.2 minipass: 7.0.4 path-type@4.0.0: {} @@ -8403,7 +8464,7 @@ snapshots: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 - react-is: 18.2.0 + react-is: 18.3.1 proc-log@3.0.0: {} @@ -8432,15 +8493,15 @@ snapshots: dependencies: safe-buffer: 5.2.1 - react-dom@18.2.0(react@18.2.0): + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 + react: 18.3.1 + scheduler: 0.23.2 - react-is@18.2.0: {} + react-is@18.3.1: {} - react@18.2.0: + react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -8470,7 +8531,7 @@ snapshots: regenerator-transform@0.15.2: dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 regexp.prototype.flags@1.5.2: dependencies: @@ -8553,7 +8614,7 @@ snapshots: es-errors: 1.3.0 is-regex: 1.1.4 - scheduler@0.23.0: + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -8566,9 +8627,9 @@ snapshots: schema-utils@4.2.0: dependencies: '@types/json-schema': 7.0.15 - ajv: 8.12.0 - ajv-formats: 2.1.1(ajv@8.12.0) - ajv-keywords: 5.1.0(ajv@8.12.0) + ajv: 8.13.0 + ajv-formats: 2.1.1(ajv@8.13.0) + ajv-keywords: 5.1.0(ajv@8.13.0) semver@6.3.1: {} @@ -8630,6 +8691,11 @@ snapshots: slash@3.0.0: {} + sonic-forest@1.0.2(tslib@2.6.2): + dependencies: + tree-dump: 1.0.1(tslib@2.6.2) + tslib: 2.6.2 + source-map-support@0.5.13: dependencies: buffer-from: 1.1.2 @@ -8771,7 +8837,7 @@ snapshots: jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 - terser: 5.30.4 + terser: 5.31.0 webpack: 5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4(webpack@5.91.0)) optionalDependencies: '@swc/core': 1.5.0 @@ -8782,7 +8848,7 @@ snapshots: jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 - terser: 5.30.4 + terser: 5.31.0 webpack: 5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.5.0 @@ -8793,12 +8859,12 @@ snapshots: jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 - terser: 5.30.4 + terser: 5.31.0 webpack: 5.91.0(@swc/core@1.5.0) optionalDependencies: '@swc/core': 1.5.0 - terser@5.30.4: + terser@5.31.0: dependencies: '@jridgewell/source-map': 0.3.6 acorn: 8.11.3 @@ -8813,6 +8879,10 @@ snapshots: text-table@0.2.0: {} + thingies@1.21.0(tslib@2.6.2): + dependencies: + tslib: 2.6.2 + thread-loader@4.0.2(webpack@5.91.0(@swc/core@1.5.0)(webpack-cli@5.1.4(webpack@5.91.0))): dependencies: json-parse-better-errors: 1.0.2 @@ -8841,20 +8911,24 @@ snapshots: dependencies: is-number: 7.0.0 + tree-dump@1.0.1(tslib@2.6.2): + dependencies: + tslib: 2.6.2 + tree-kill@1.2.2: {} ts-api-utils@1.3.0(typescript@5.4.5): dependencies: typescript: 5.4.5 - ts-node@10.9.1(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5): + ts-node@10.9.1(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.12.7 + '@types/node': 20.12.8 acorn: 8.11.3 acorn-walk: 8.3.2 arg: 4.1.3 @@ -8867,14 +8941,14 @@ snapshots: optionalDependencies: '@swc/core': 1.5.0 - ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.7)(typescript@5.4.5): + ts-node@10.9.2(@swc/core@1.5.0)(@types/node@20.12.8)(typescript@5.4.5): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.12.7 + '@types/node': 20.12.8 acorn: 8.11.3 acorn-walk: 8.3.2 arg: 4.1.3 @@ -8949,11 +9023,11 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - typescript-eslint@7.7.1(eslint@9.1.1)(typescript@5.4.5): + typescript-eslint@7.8.0(eslint@9.1.1)(typescript@5.4.5): dependencies: - '@typescript-eslint/eslint-plugin': 7.7.1(@typescript-eslint/parser@7.7.1(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5) - '@typescript-eslint/parser': 7.7.1(eslint@9.1.1)(typescript@5.4.5) - '@typescript-eslint/utils': 7.7.1(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 7.8.0(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/parser': 7.8.0(eslint@9.1.1)(typescript@5.4.5) + '@typescript-eslint/utils': 7.8.0(eslint@9.1.1)(typescript@5.4.5) eslint: 9.1.1 optionalDependencies: typescript: 5.4.5 @@ -8986,7 +9060,7 @@ snapshots: universalify@2.0.1: {} - update-browserslist-db@1.0.13(browserslist@4.23.0): + update-browserslist-db@1.0.14(browserslist@4.23.0): dependencies: browserslist: 4.23.0 escalade: 3.1.2 @@ -9038,7 +9112,7 @@ snapshots: colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 - envinfo: 7.12.0 + envinfo: 7.13.0 fastest-levenshtein: 1.0.16 import-local: 3.1.0 interpret: 3.1.1 @@ -9066,7 +9140,7 @@ snapshots: browserslist: 4.23.0 chrome-trace-event: 1.0.3 enhanced-resolve: 5.16.0 - es-module-lexer: 1.5.0 + es-module-lexer: 1.5.2 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -9097,7 +9171,7 @@ snapshots: browserslist: 4.23.0 chrome-trace-event: 1.0.3 enhanced-resolve: 5.16.0 - es-module-lexer: 1.5.0 + es-module-lexer: 1.5.2 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -9130,7 +9204,7 @@ snapshots: browserslist: 4.23.0 chrome-trace-event: 1.0.3 enhanced-resolve: 5.16.0 - es-module-lexer: 1.5.0 + es-module-lexer: 1.5.2 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -9175,6 +9249,8 @@ snapshots: wildcard@2.0.1: {} + word-wrap@1.2.5: {} + wrap-ansi@5.1.0: dependencies: ansi-styles: 3.2.1 From 85220be771d96bd7391fd274764c446464cfac56 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Fri, 3 May 2024 01:20:16 +0200 Subject: [PATCH 28/52] e Disables linting warnings in vscode, removes extra warnings --- .vscode/settings.json | 5 ++++- packages/test/src/bar-addon.test.ts | 1 - packages/testing/src/compilation/environment.spec.ts | 1 - pnpm-lock.yaml | 3 --- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 73e53e8b..31a1f64d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,8 @@ "search.exclude": { "pnpm-lock.yaml": true }, - "typescript.tsdk": "node_modules/typescript/lib" + "typescript.tsdk": "node_modules/typescript/lib", + "eslint.useESLintClass": true, + "eslint.problems.shortenToSingleLine": true, + "eslint.quiet": true } diff --git a/packages/test/src/bar-addon.test.ts b/packages/test/src/bar-addon.test.ts index ca17502f..46b0961c 100644 --- a/packages/test/src/bar-addon.test.ts +++ b/packages/test/src/bar-addon.test.ts @@ -4,7 +4,6 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { compilationEnv } from "@quatico/websmith-testing"; import { join } from "path"; diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index 831e0988..2d645b67 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-call */ /* * --------------------------------------------------------------------------------------------- * Copyright (c) Quatico Solutions AG. All rights reserved. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7a7383d..0f80f1f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -436,9 +436,6 @@ importers: '@nx/eslint-plugin': specifier: ^18.3.4 version: 18.3.4(@babel/traverse@7.24.5)(@swc/core@1.5.0)(@types/node@20.12.8)(@typescript-eslint/parser@7.8.0(eslint@9.1.1)(typescript@5.4.5))(eslint-config-prettier@9.1.0(eslint@9.1.1))(eslint@9.1.1)(nx@18.3.4(@swc/core@1.5.0))(typescript@5.4.5) - '@quatico/websmith-compiler': - specifier: workspace:* - version: link:../compiler '@quatico/websmith-core': specifier: workspace:* version: link:../core From 5d49e24547cc057ef4c39f3ba8b875d6aacf8fd9 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Fri, 3 May 2024 01:36:29 +0200 Subject: [PATCH 29/52] e Adds examples test to test:e2e target --- packages/examples/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/examples/package.json b/packages/examples/package.json index 36f3f956..dc189f13 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -7,15 +7,15 @@ "private": true, "scripts": { "clean": "rimraf lib dist bin coverage", - "lint": "eslint \"{src,test}/**/*.ts\" --color", + "lint": "eslint \"{src,tests}/**/*.ts\" --color", "lint:fix": "pnpm lint --fix", "build": "tsc", "execute": "websmith --addons example-generator,example-processor,example-transformer,example-result-processor -p tsconfig.execute.json", "watch": "tsc --watch", "watch:test": "jest --watch", - "test": "jest --coverage --passWithNoTests", + "test:e2e": "jest --coverage", "test:update-snapshots": "pnpm test -u", - "dist": "cross-env-shell NODE_ENV=production \"pnpm clean && pnpm lint && pnpm test && pnpm build\"" + "dist": "cross-env-shell NODE_ENV=production \"pnpm clean && pnpm lint && pnpm build\"" }, "devDependencies": { "@eslint/js": "^9.1.1", From a81b6671a00a28082d8572bcfa068a336680e3c6 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Fri, 3 May 2024 10:18:59 +0200 Subject: [PATCH 30/52] r Replaces deprecated rmdirSync with rmSync --- packages/testing/src/compilation/environment.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 73b00865..ac07f111 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -5,7 +5,7 @@ * --------------------------------------------------------------------------------------------- */ import { AddonRegistry, Compiler, createBrowserSystem, type CompilerAddon, type CompilerOptions } from "@quatico/websmith-core"; -import { rmdirSync } from "fs"; +import { rmSync } from "fs"; import { basename, dirname, extname, isAbsolute, join } from "path"; import requireFromString from "require-from-string"; import ts from "typescript"; @@ -83,7 +83,7 @@ export class CompilationEnv { if (this.isVirtual()) { this.system.readDirectory(target).forEach(it => this.system.deleteFile!(it)); } else { - rmdirSync(target, { recursive: true }); + rmSync(target, { recursive: true }); } } return this; @@ -252,7 +252,6 @@ export class CompilationEnv { public getCompiledFiles(): ProjectFiles { return projectFiles(this.system.readDirectory(this.getCompiledDir()).map(it => projectFile(this.getSystem(), this.buildDir, it))); - } public getCompiledFile(filePath: string): ProjectFile | undefined { @@ -331,7 +330,7 @@ export type CompilationOptions = { virtual?: boolean; }; -export type ProjectFiles = ProjectFile[] & { getPaths: () => string[], getContents: () => string[] }; +export type ProjectFiles = ProjectFile[] & { getPaths: () => string[]; getContents: () => string[] }; export interface ProjectFile { getPath(): string; @@ -363,8 +362,6 @@ const isFiles = (source?: string | Record): source is Record { return Object.assign(result, { getPaths: () => result.map(it => it.getPath()), getContents: () => result.map(it => it.getContent()!) }); -} +}; export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => new CompilationEnv(rootDir, options); - - From 30b5b1cfb713492f0825e83223068be2553c955c Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Fri, 3 May 2024 10:20:09 +0200 Subject: [PATCH 31/52] r Introduces type CompilerAddons to improve usage over native array --- .../core/src/compiler/addons/AddonRegistry.ts | 56 +++++++++++-------- .../core/src/compiler/addons/CompilerAddon.ts | 4 ++ 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index 679ec2be..61f8b4e0 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -8,7 +8,7 @@ import { Reporter, WarnMessage } from "@quatico/websmith-api"; import path, { basename, extname } from "path"; import ts from "typescript"; import { CompilationConfig } from "../config"; -import { CompilerAddon } from "./CompilerAddon"; +import type { CompilerAddon, CompilerAddons } from "./CompilerAddon"; export type AddonRegistryOptions = { addons?: string; @@ -33,13 +33,18 @@ export class AddonRegistry { this.availableAddons = this.findAddons(); } - public getAvailableAddons(target?: string): CompilerAddon[] { - const expected = getAddonNames(target, this.addons, this.options.config); - if (expected.length > 0) { - this.reportMissingAddons(target, expected); - return expected.map(it => this.availableAddons.get(it)).filter(it => it !== undefined) as CompilerAddon[]; + public getAvailableAddons(target?: string): CompilerAddons { + const expectedNames = getAddonNames(target, this.addons, this.options.config); + let results: CompilerAddon[]; + if (expectedNames.length > 0) { + this.reportMissingAddons(target, expectedNames); + results = Object.entries(this.availableAddons) + .filter(([name]) => expectedNames.includes(name)) + .map(([, addon]) => addon); + } else { + results = Array.from(this.availableAddons.values()); } - return Array.from(this.availableAddons.values()); + return Object.assign(results, { getNames: () => results.map(it => it.getName()) }); } public getAddonsDir(): string { @@ -74,23 +79,30 @@ export class AddonRegistry { if (addonsDir) { system .readDirectory(addonsDir, [".js", ".jsx"]) - .filter(ad => basename(ad, extname(ad)).toLocaleLowerCase() === "addon") - .forEach(it => { - const importPath = system.resolvePath(it); - const modulePath = extname(importPath).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) - ? importPath.replace(extname(importPath), "") - : importPath; - // eslint-disable-next-line @typescript-eslint/no-var-requires - const activator = require(modulePath).activate; - const name = it - .replace(path.sep + basename(it), "") + .filter(dirName => basename(dirName, extname(dirName)).toLocaleLowerCase() === "addon") + .forEach(filePath => { + const addonName = filePath + .replace(path.sep + basename(filePath), "") .split(path.sep) .slice(-1)[0]; - if (name && map.has(name)) { - reporter.reportDiagnostic(new WarnMessage(`Duplicate addon name "${name}" in "${addonsDir}".`)); - } - if (name && activator && !map.has(name)) { - map.set(name, { getName: () => name, activate: activator }); + if (addonName) { + if (map.has(addonName)) { + reporter.reportDiagnostic(new WarnMessage(`Duplicate addon name "${addonName}" in "${addonsDir}".`)); + } else { + const resolvedPath = system.resolvePath(filePath); + const importPath = extname(resolvedPath).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) + ? resolvedPath.replace(extname(resolvedPath), "") + : resolvedPath; + // eslint-disable-next-line @typescript-eslint/no-var-requires + const activator = require(importPath).activate; + if (activator) { + map.set(addonName, { getName: () => addonName, activate: activator }); + } else { + reporter.reportDiagnostic( + new WarnMessage(`No "activate" function found for addon "${addonName}" in "${addonsDir}".`) + ); + } + } } }); } diff --git a/packages/core/src/compiler/addons/CompilerAddon.ts b/packages/core/src/compiler/addons/CompilerAddon.ts index f1e0e132..8f556659 100644 --- a/packages/core/src/compiler/addons/CompilerAddon.ts +++ b/packages/core/src/compiler/addons/CompilerAddon.ts @@ -13,3 +13,7 @@ export interface CompilerAddon { getName: () => string; activate: (context: AddonContext) => void; } + +export type CompilerAddons = CompilerAddon[] & { + getNames: () => string[]; +}; From 693bbc08ab891513b87399f34ab3de39f163d99c Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Fri, 3 May 2024 10:20:37 +0200 Subject: [PATCH 32/52] t Provides additional unit tests for AddonRegistry --- .../src/compiler/addons/AddonRegistry.spec.ts | 251 +++++++++++++----- 1 file changed, 187 insertions(+), 64 deletions(-) diff --git a/packages/core/src/compiler/addons/AddonRegistry.spec.ts b/packages/core/src/compiler/addons/AddonRegistry.spec.ts index e46fd631..65cdbf9b 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.spec.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.spec.ts @@ -54,91 +54,42 @@ describe("getAddons", () => { it("returns empty addons w/ empty addons directory", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAvailableAddons()).toEqual([]); + expect(testObj.getAvailableAddons()).toHaveLength(0); }); it("returns addons w/ single addon in addon directory", () => { - system.writeFile("./addons/expected/addon.js", "export const activate = () => {};"); - jest.mock( - "/addons/expected/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); + createAddon("addons/expected/addon"); const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAvailableAddons().map(it => it.getName())).toEqual(["expected"]); + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); }); it("returns addons w/ multiple addons in addon directory", () => { - system.writeFile("./addons/one/addon.js", "export const activate = () => {};"); - jest.mock( - "/addons/one/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); - system.writeFile("./addons/two/addon.js", "export const activate = () => {};"); - jest.mock( - "/addons/two/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); - system.writeFile("./addons/three/addon.js", "export const activate = () => {};"); - jest.mock( - "/addons/three/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); - - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - - expect(testObj.getAvailableAddons().map(it => it.getName())).toEqual(["one", "two", "three"]); + createAddon("addons/one/addon"); + createAddon("addons/two/addon"); + createAddon("addons/three/addon"); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["one", "two", "three"]); }); it("returns valid addons w/ invalid and valid addons in addon directory", () => { - system.writeFile("./addons/expected/addon.js", "export const activate = () => {};"); - jest.mock( - "/addons/expected/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); - system.writeFile("./addons/invalid/addon.js", "export const whatever = () => {};"); - jest.mock( - "/addons/invalid/addon", - () => { - return { whatever: jest.fn() }; - }, - { virtual: true } - ); + createAddon("addons/expected/addon"); + createAddon("addons/invalid/addon", "export const whatever = () => {};", { whatever: jest.fn() }); const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAvailableAddons().map(it => it.getName())).toEqual(["expected"]); + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); }); it("returns no addons w/ empty files in addon directory", () => { - system.writeFile("./addons/empty/addon.js", ""); - jest.mock( - "/addons/empty/addon", - () => { - return {}; - }, - { virtual: true } - ); + createAddon("addons/empty/addon", "", {}); const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - expect(testObj.getAvailableAddons()).toEqual([]); + expect(testObj.getAvailableAddons()).toHaveLength(0); }); it("reports warning w/ non-existing addons name", () => { @@ -169,3 +120,175 @@ describe("getAddons", () => { expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "target": "does-not-exist".')); }); }); + +describe("getAddonsDir", () => { + it("returns addons directory with addonsDir config", () => { + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAddonsDir()).toEqual("./addons"); + }); + + it("returns undefined w/o addons directory", () => { + const testObj = new AddonRegistry({ reporter, system } as any); + + expect(testObj.getAddonsDir()).toBeUndefined(); + }); +}); + +describe("refresh", () => { + it("refreshes addons w/ new addons", () => { + createAddon("addons/expected/addon"); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); + + createAddon("addons/new/addon"); + + testObj.refresh(); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected", "new"]); + }); + + it("refreshes addons w/o new addons", () => { + createAddon("addons/expected/addon"); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); + + testObj.refresh(); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); + }); + + it("refreshes addons w/ removed addons", () => { + createAddon("addons/expected/addon"); + createAddon("addons/removed/addon"); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected", "removed"]); + + removeAddon("addons/removed/addon"); + + testObj.refresh(); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); + }); + + it("refreshes addons w/ empty addons directory", () => { + createAddon("addons/expected/addon"); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); + + removeAddon("addons/expected/addon"); + + testObj.refresh(); + + expect(testObj.getAvailableAddons()).toHaveLength(0); + }); +}); + +describe("reportMissingAddons", () => { + it("reports missing addons directory", () => { + reporter.reportDiagnostic = jest.fn(); + + const testObj = new AddonRegistry({ addonsDir: "./expected", reporter, system }); + + // @ts-expect-error private property access + testObj.reportMissingAddons(undefined, []); + + expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Addons directory "./expected" does not exist.')); + }); + + it("reports missing addons w/ target", () => { + system.createDirectory("./addons"); + reporter.reportDiagnostic = jest.fn(); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + // @ts-expect-error private property access + testObj.reportMissingAddons("my-target", ["missing"]); + + expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "my-target": "missing".')); + }); + + it("reports missing addons w/o target", () => { + system.createDirectory("./addons"); + reporter.reportDiagnostic = jest.fn(); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + // @ts-expect-error private property access + testObj.reportMissingAddons(undefined, ["missing"]); + + expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons: "missing".')); + }); + + it("does not report missing addons w/o missing addons", () => { + system.createDirectory("./addons"); + reporter.reportDiagnostic = jest.fn(); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + // @ts-expect-error private property access + testObj.reportMissingAddons(undefined, []); + + expect(reporter.reportDiagnostic).not.toHaveBeenCalled(); + }); +}); + +describe("findAddons", () => { + it("finds addons w/ single addon in addons directory", () => { + createAddon("addons/expected/addon"); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); + }); + + it("finds addons w/ multiple addons in addons directory", () => { + createAddon("addons/one/addon"); + createAddon("addons/two/addon"); + createAddon("addons/three/addon"); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["one", "two", "three"]); + }); + + it("finds valid addons w/ invalid and valid addons in addons directory", () => { + createAddon("addons/expected/addon"); + createAddon("addons/invalid/addon", "export const whatever = () => {};", { whatever: jest.fn() }); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); + }); + + it("finds no addons w/ empty files in addons directory", () => { + createAddon("addons/empty/addon", "", {}); + + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + + expect(testObj.getAvailableAddons()).toHaveLength(0); + }); +}); + +const createAddon = (path: string, code = "export const activate = () => {};", mock: object = { activate: jest.fn() }) => { + system.writeFile(`./${path}.js`, code); + jest.mock( + `/${path}`, + () => { + return mock; + }, + { virtual: true } + ); +}; + +const removeAddon = (path: string) => { + system.deleteFile!(`./${path}.js`); +}; From e02428a1fdb2b78011851a7ae4d439085d72f1a5 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Fri, 3 May 2024 11:27:16 +0200 Subject: [PATCH 33/52] r Restructure state handling in AddonRegistry to isolate expected and missing addons names --- .../src/compiler/addons/AddonRegistry.spec.ts | 145 +++++++++++++----- .../core/src/compiler/addons/AddonRegistry.ts | 89 +++++------ .../src/compiler/config/CompilationConfig.ts | 4 +- 3 files changed, 158 insertions(+), 80 deletions(-) diff --git a/packages/core/src/compiler/addons/AddonRegistry.spec.ts b/packages/core/src/compiler/addons/AddonRegistry.spec.ts index 65cdbf9b..aa9f0693 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.spec.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.spec.ts @@ -5,7 +5,7 @@ * --------------------------------------------------------------------------------------------- */ import { WarnMessage } from "@quatico/websmith-api"; -import ts from "typescript"; +import ts, { sys } from "typescript"; import { ReporterMock, compileSystem } from "../../../test"; import { AddonRegistry } from "./AddonRegistry"; @@ -34,23 +34,9 @@ describe("Ctor", () => { expect(reporter.reportDiagnostic).not.toHaveBeenCalled(); }); - - it("yields addons w/o addons property", () => { - const testObj = new AddonRegistry({} as any); - - // @ts-expect-error private property access - expect(testObj.addons).toEqual([]); - }); - - it("yields addons w/ addons property", () => { - const testObj = new AddonRegistry({ addons: "zip,zap, zup" } as any); - - // @ts-expect-error private property access - expect(testObj.addons).toEqual(["zip", "zap", "zup"]); - }); }); -describe("getAddons", () => { +describe("getAvailableAddons", () => { it("returns empty addons w/ empty addons directory", () => { const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); @@ -192,6 +178,83 @@ describe("refresh", () => { }); }); +describe("getExpectedAddons", () => { + it("returns empty w/o addons", () => { + const testObj = new AddonRegistry({ addonsDir: "./empty", reporter, system }); + + // @ts-expect-error private property access + expect(testObj.getExpectedAddons()).toHaveLength(0); + }); + + it("returns addons w/ addons", () => { + const testObj = new AddonRegistry({ addons: "one, two, three", addonsDir: "./empty", reporter, system }); + + // @ts-expect-error private property access + expect(testObj.getExpectedAddons()).toEqual(["one", "two", "three"]); + }); + + it("returns target addons w/ target", () => { + const testObj = new AddonRegistry({ + config: { targets: { target: { addons: ["one", "two", "three"] } }, configFilePath: "" }, + addonsDir: "./empty", + reporter, + system, + }); + + // @ts-expect-error private property access + expect(testObj.getExpectedAddons("target")).toEqual(["one", "two", "three"]); + }); + + it("returns empty w/ target and no addons", () => { + const testObj = new AddonRegistry({ + config: { targets: { target: { addons: [] } }, configFilePath: "" }, + addonsDir: "./empty", + reporter, + system, + }); + + // @ts-expect-error private property access + expect(testObj.getExpectedAddons("target")).toHaveLength(0); + }); + + it("returns empty w/ target and no target", () => { + const testObj = new AddonRegistry({ + config: { targets: { target: { addons: ["one", "two", "three"] } }, configFilePath: "" }, + addonsDir: "./empty", + reporter, + system, + }); + + // @ts-expect-error private property access + expect(testObj.getExpectedAddons()).toHaveLength(0); + }); +}); + +describe("getMissingAddons", () => { + it("returns empty w/o addons", () => { + const testObj = new AddonRegistry({ addonsDir: "./target", reporter, system }); + + // @ts-expect-error private property access + expect(testObj.getMissingAddons()).toHaveLength(0); + }); + + it("returns missing addons w/ missing addons", () => { + const testObj = new AddonRegistry({ addons: "missing", addonsDir: "./target", reporter, system }); + + // @ts-expect-error private property access + expect(testObj.getMissingAddons()).toEqual(["missing"]); + }); + + it("returns missing addons w/ missing and available addons", () => { + createAddon("target/expected/addon"); + + const testObj = new AddonRegistry({ addons: "missing, expected", addonsDir: "./target", reporter, system }); + + // @ts-expect-error private property access + expect(testObj.getMissingAddons()).toEqual(["missing"]); + }); +}); + describe("reportMissingAddons", () => { it("reports missing addons directory", () => { reporter.reportDiagnostic = jest.fn(); @@ -204,38 +267,50 @@ describe("reportMissingAddons", () => { expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Addons directory "./expected" does not exist.')); }); - it("reports missing addons w/ target", () => { - system.createDirectory("./addons"); + it("reports missing addons w/ missing addons", () => { + system.createDirectory("./target"); reporter.reportDiagnostic = jest.fn(); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + new AddonRegistry({ addonsDir: "./target", addons: "missing", reporter, system }).getAvailableAddons(); - // @ts-expect-error private property access - testObj.reportMissingAddons("my-target", ["missing"]); - - expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "my-target": "missing".')); + expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons: "missing".')); }); - it("reports missing addons w/o target", () => { - system.createDirectory("./addons"); + it("does not report missing addons w/o missing addons", () => { + system.createDirectory("./target"); + createAddon("target/expected/addon"); reporter.reportDiagnostic = jest.fn(); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); - - // @ts-expect-error private property access - testObj.reportMissingAddons(undefined, ["missing"]); + new AddonRegistry({ addonsDir: "./target", addons: "expected", reporter, system }).getAvailableAddons(); - expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons: "missing".')); + expect(reporter.reportDiagnostic).not.toHaveBeenCalled(); }); - it("does not report missing addons w/o missing addons", () => { - system.createDirectory("./addons"); + it("reports missing target addons w/ missing target addons", () => { + system.createDirectory("./target"); reporter.reportDiagnostic = jest.fn(); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + new AddonRegistry({ + config: { targets: { target: { addons: ["missing"] } }, configFilePath: "" }, + addonsDir: "./target", + reporter, + system, + }).getAvailableAddons("target"); - // @ts-expect-error private property access - testObj.reportMissingAddons(undefined, []); + expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "target": "missing".')); + }); + + it("does not report missing target addons w/o missing target addons", () => { + system.createDirectory("./target"); + createAddon("target/expected/addon"); + reporter.reportDiagnostic = jest.fn(); + + new AddonRegistry({ + config: { targets: { target: { addons: ["expected"] } }, configFilePath: "" }, + addonsDir: "./target", + reporter, + system, + }).getAvailableAddons("target"); expect(reporter.reportDiagnostic).not.toHaveBeenCalled(); }); diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index 61f8b4e0..b9b6ab1d 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -19,54 +19,73 @@ export type AddonRegistryOptions = { }; export class AddonRegistry { - private addons: string[]; private availableAddons: Map; private options: AddonRegistryOptions; constructor(options: AddonRegistryOptions) { this.options = options; - this.addons = - options.addons - ?.split(",") - .map(it => it.trim()) - .filter(it => it.length > 0) ?? []; this.availableAddons = this.findAddons(); } - public getAvailableAddons(target?: string): CompilerAddons { - const expectedNames = getAddonNames(target, this.addons, this.options.config); - let results: CompilerAddon[]; - if (expectedNames.length > 0) { - this.reportMissingAddons(target, expectedNames); - results = Object.entries(this.availableAddons) - .filter(([name]) => expectedNames.includes(name)) - .map(([, addon]) => addon); - } else { - results = Array.from(this.availableAddons.values()); - } - return Object.assign(results, { getNames: () => results.map(it => it.getName()) }); - } - public getAddonsDir(): string { return this.options.addonsDir; } + public getAvailableAddons(target?: string): CompilerAddons { + this.reportMissingAddons(target); + const expectedNames = this.getExpectedAddons(target); + const results = + expectedNames.length > 0 + ? Object.entries(this.availableAddons) + .filter(([name]) => expectedNames.includes(name)) + .map(([, addon]) => addon) + : Array.from(this.availableAddons.values()); + return Object.assign(results, { getNames: () => results.map(it => it.getName()) }); + } + public refresh(): this { this.availableAddons = this.findAddons(); return this; } - private reportMissingAddons(target: string | undefined, expected: string[]): void { - const { reporter } = this.options; - const missing = expected.filter(name => !this.availableAddons.has(name)); - if (missing.length > 0) { - if (target && target !== "*") { - reporter.reportDiagnostic(new WarnMessage(`Missing addons for target "${target}": "${missing.join(", ")}".`)); + private getExpectedAddons(target?: string): string[] { + const { config, addons } = this.options; + const requestedAddons = + addons + ?.split(",") + .map(it => it.trim()) + .filter(it => it.length > 0) ?? []; + + if (requestedAddons.length > 0) { + return requestedAddons; + } + + if (config) { + if (target) { + const { targets = {} } = config; + return targets[target]?.addons ?? []; } else { - reporter.reportDiagnostic(new WarnMessage(`Missing addons: "${missing.join(", ")}".`)); + return config.addons ?? []; } } + return []; } + + private getMissingAddons(target?: string): string[] { + return this.getExpectedAddons(target).filter(name => !this.availableAddons.has(name)); + } + + private reportMissingAddons(target?: string): void { + const { reporter } = this.options; + + const missing = this.getMissingAddons(target).join(", "); + if (missing.length > 0) { + reporter.reportDiagnostic( + new WarnMessage(target && target !== "*" ? `Missing addons for target "${target}": "${missing}".` : `Missing addons: "${missing}".`) + ); + } + } + private findAddons(): Map { const { addonsDir, reporter, system } = this.options; const map = new Map(); @@ -109,19 +128,3 @@ export class AddonRegistry { return map; } } - -const getAddonNames = (target: string | undefined, expectedAddons: string[], config?: CompilationConfig): string[] => { - if (expectedAddons.length > 0) { - return expectedAddons; - } - - if (config) { - if (target) { - const { targets = {} } = config; - return targets[target]?.addons ?? []; - } else { - return config.addons ?? []; - } - } - return []; -}; diff --git a/packages/core/src/compiler/config/CompilationConfig.ts b/packages/core/src/compiler/config/CompilationConfig.ts index c27faaa3..6bf6130b 100644 --- a/packages/core/src/compiler/config/CompilationConfig.ts +++ b/packages/core/src/compiler/config/CompilationConfig.ts @@ -7,9 +7,9 @@ import type { TargetConfig } from "@quatico/websmith-api"; export type CompilationConfig = { - configFilePath: string; - addonsDir?: string; addons?: string[]; + addonsDir?: string; + configFilePath: string; targets?: Record; transpileOnly?: boolean; }; From 0117f30e59a23add60d06fb45f9db4166a54dbc6 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 5 May 2024 14:22:26 +0200 Subject: [PATCH 34/52] t Inline compile system in every test --- packages/compiler/src/command.spec.ts | 173 ++++++++++---------------- 1 file changed, 69 insertions(+), 104 deletions(-) diff --git a/packages/compiler/src/command.spec.ts b/packages/compiler/src/command.spec.ts index ad279a3c..ff6254ee 100644 --- a/packages/compiler/src/command.spec.ts +++ b/packages/compiler/src/command.spec.ts @@ -6,7 +6,7 @@ * --------------------------------------------------------------------------------------------- */ import { WarnMessage } from "@quatico/websmith-api"; -import { Compiler, CompilerAddon, NoReporter } from "@quatico/websmith-core"; +import { Compiler, NoReporter } from "@quatico/websmith-core"; import { compileSystem } from "@quatico/websmith-testing"; import { Command } from "commander"; import path from "path"; @@ -14,14 +14,9 @@ import ts from "typescript"; import { addCompileCommand, hasInvalidTargets } from "./command"; import { createOptions } from "./options"; -let testSystem: ts.System; - -beforeEach(() => { - testSystem = compileSystem().fileSystem; -}); - describe("addCompileCommand", () => { it("should yield additionalArguments w/ unknown argument", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); const testObj = addCompileCommand(new Command(), target); @@ -49,6 +44,7 @@ describe("addCompileCommand", () => { }); it("should yield default options w/o config and w/o CLI arguments", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse([], { from: "user" }); @@ -106,8 +102,8 @@ describe("addCompileCommand", () => { }); it("should yield config option w/ --config cli argument", () => { - testSystem.writeFile("./expected/websmith.config.json", "{}"); - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const testSystem = compileSystem({ "./expected/websmith.config.json": "{}" }).fileSystem; + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--config", "./expected/websmith.config.json"], { from: "user" }); @@ -115,8 +111,8 @@ describe("addCompileCommand", () => { }); it("should yield project option w/ --project cli argument", () => { - testSystem.writeFile("expected/tsconfig.json", "{}"); - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const testSystem = compileSystem({ "./expected/tsconfig.json": "{}" }).fileSystem; + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--project", "expected/tsconfig.json"], { from: "user" }); @@ -124,6 +120,7 @@ describe("addCompileCommand", () => { }); it("should yield sourceMap option w/ --sourceMap cli argument", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--sourceMap"], { from: "user" }); @@ -132,6 +129,7 @@ describe("addCompileCommand", () => { }); it("should yield debug compiler option w/ --debug cli argument", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--debug"], { from: "user" }); @@ -140,7 +138,8 @@ describe("addCompileCommand", () => { }); it("should yield watch compiler option w/ --watch cli argument", () => { - const target = new Compiler(createOptions({}, new NoReporter())); + const testSystem = compileSystem().fileSystem; + const target = new Compiler(createOptions({}, new NoReporter(), testSystem)); target.registerWatch = jest.fn(); // prevent register of watch task addCompileCommand(new Command(), target).parse(["--watch"], { from: "user" }); @@ -149,8 +148,8 @@ describe("addCompileCommand", () => { }); it("should yield transpileOnly option w/ --transpileOnly cli argument", () => { - testSystem.writeFile("expected/tsconfig.json", "{}"); - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const testSystem = compileSystem({ "./expected/tsconfig.json": "{}" }).fileSystem; + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--transpileOnly"], { from: "user" }); @@ -161,6 +160,7 @@ describe("addCompileCommand", () => { console.error = line => { throw new Error(line.toString()); }; + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--debug", "--allowJs", "--strict"], { from: "user" }); @@ -174,7 +174,8 @@ describe("addCompileCommand", () => { }); it("should call compile w/o --watch cli argument", () => { - const target = new Compiler(createOptions({}, new NoReporter())); + const testSystem = compileSystem().fileSystem; + const target = new Compiler(createOptions({}, new NoReporter(), testSystem)); target.compile = jest.fn(); addCompileCommand(new Command(), target).parse([], { from: "user" }); @@ -183,7 +184,8 @@ describe("addCompileCommand", () => { }); it("should call watch w/ --watch cli argument", () => { - const target = new Compiler(createOptions({}, new NoReporter())); + const testSystem = compileSystem().fileSystem; + const target = new Compiler(createOptions({}, new NoReporter(), testSystem)); target.watch = jest.fn(); addCompileCommand(new Command(), target).parse(["--watch"], { from: "user" }); @@ -194,6 +196,7 @@ describe("addCompileCommand", () => { describe("addCompileCommand#addons", () => { it("should yield warning w/ --addonsDir cli argument to non-existing path", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); target.getReporter().reportDiagnostic = jest.fn(); @@ -203,96 +206,48 @@ describe("addCompileCommand#addons", () => { }); it("should yield options addons w/ --addons cli argument and existing addon", () => { - jest.mock( - "/addons/expected/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); - testSystem.writeFile("./addons/expected/addon.js", "export const activate = () => {};"); + const testSystem = compileSystem().fileSystem; + createAddon(testSystem, "addons/expected/addon"); const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--addons", "expected"], { from: "user" }); - expect( - target - .getOptions() - .addons.getAvailableAddons() - .map((it: CompilerAddon) => it.getName()) - ).toEqual(["expected"]); + expect(target.getOptions().addons.refresh().getAvailableAddons().getNames()).toEqual(["expected"]); }); it("should yield options addons w/ --addons cli argument and multiple existing addons", () => { - testSystem.writeFile("./addons/zip/addon.js", "export const activate = () => {};"); - testSystem.writeFile("./addons/zap/addon.js", "export const activate = () => {};"); - testSystem.writeFile("./addons/zup/addon.js", "export const activate = () => {};"); - jest.mock( - "/addons/zip/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); - - jest.mock( - "/addons/zap/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); - - jest.mock( - "/addons/zup/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); + const testSystem = compileSystem().fileSystem; + createAddon(testSystem, "addons/zip/addon"); + createAddon(testSystem, "addons/zap/addon"); + createAddon(testSystem, "addons/zup/addon"); const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--addons", "zip, zap, zup"], { from: "user" }); - expect( - target - .getOptions() - .addons.getAvailableAddons() - .map((it: CompilerAddon) => it.getName()) - ).toEqual(["zip", "zap", "zup"]); + expect(target.getOptions().addons.refresh().getAvailableAddons().getNames()).toEqual(["zip", "zap", "zup"]); }); it("should yield empty options addons w/ --addons cli argument and non-existing addon", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--addons", "unknown"], { from: "user" }); - expect(target.getOptions().addons.getAvailableAddons()).toEqual([]); + expect(target.getOptions().addons.getAvailableAddons()).toHaveLength(0); }); it("should not yield non-existing options addons w/ --addons cli argument, existing and non-existing addons", () => { - testSystem.writeFile("./addons/expected/addon.js", "export const activate = () => {};"); - jest.mock( - "/addons/expected/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); - - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const testSystem = compileSystem().fileSystem; + createAddon(testSystem, "addons/expected/addon"); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--addons", "unknown, expected"], { from: "user" }); - expect( - target - .getOptions() - .addons.getAvailableAddons() - .map((it: CompilerAddon) => it.getName()) - ).toEqual(["expected"]); + expect(target.getOptions().addons.refresh().getAvailableAddons().getNames()).toEqual(["expected"]); }); it("should yield warning w/ --addons cli argument and non-existing addon name", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); target.getReporter().reportDiagnostic = jest.fn(); @@ -302,16 +257,9 @@ describe("addCompileCommand#addons", () => { }); it("should yield warning w/ --addons cli argument, existing and non-existing addons", () => { - testSystem.writeFile("./addons/existing/addon.js", "export const activate = () => {};"); - jest.mock( - "/addons/existing/addon", - () => { - return { activate: jest.fn() }; - }, - { virtual: true } - ); - - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const testSystem = compileSystem({ "./websmith.config.json": "{}" }).fileSystem; + createAddon(testSystem, "addons/existing/addon"); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); target.getReporter().reportDiagnostic = jest.fn(); addCompileCommand(new Command(), target).parse(["--addons", "existing, unknown"], { from: "user" }); @@ -320,21 +268,19 @@ describe("addCompileCommand#addons", () => { }); it("should yield addonsDir and addons from compiler config w/o any cli argument", () => { - testSystem.writeFile("/expected/one/addon.js", "export const activate = () => {};"); - jest.mock( - "/expected/one/addon", - () => { - return { activate: () => undefined }; - }, - { virtual: true } - ); + const testSystem = compileSystem().fileSystem; + createAddon(testSystem, "expected/one/addon"); testSystem.writeFile("websmith.config.json", '{ "addons":["one", "two"], "addonsDir":"./expected" }'); - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse([], { from: "user" }); expect(target.getOptions().addons).toMatchObject({ - addons: ["one", "two"], + options: { + addons: "one,two", + addonsDir: "/expected", + config: { addons: ["one", "two"], addonsDir: "/expected", configFilePath: "/websmith.config.json" }, + }, availableAddons: {}, }); }); @@ -342,6 +288,7 @@ describe("addCompileCommand#addons", () => { describe("addCompileCommand#targets", () => { it("should yield options targets w/ --targets cli argument and single value", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({ project: "./tsconfig.json" }, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--targets", "expected"], { from: "user" }); @@ -350,6 +297,7 @@ describe("addCompileCommand#targets", () => { }); it("should yield options targets w/ --targets cli argument and comma separated values", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--targets", "one, two, three"], { from: "user" }); @@ -358,6 +306,7 @@ describe("addCompileCommand#targets", () => { }); it("should yield warning w/ --targets cli argument and unknown name", () => { + const testSystem = compileSystem().fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); target.getReporter().reportDiagnostic = jest.fn(); @@ -371,8 +320,9 @@ describe("addCompileCommand#targets", () => { }); it("should not yield any warning w/ --targets cli argument and known names", () => { + const testSystem = compileSystem().fileSystem; testSystem.writeFile("./websmith.config.json", '{ "targets": {"expected": {}} }'); - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); target.getReporter().reportDiagnostic = jest.fn(); addCompileCommand(new Command(), target).parse(["--targets", "expected"], { from: "user" }); @@ -381,8 +331,9 @@ describe("addCompileCommand#targets", () => { }); it("should not yield any warning w/ --targets cli argument and multiple known names", () => { + const testSystem = compileSystem().fileSystem; testSystem.writeFile("./websmith.config.json", '{ "targets": {"zip": {}, "zap": {}, "zup": {}} }'); - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); target.getReporter().reportDiagnostic = jest.fn(); addCompileCommand(new Command(), target).parse(["--targets", "zip, zap, zup"], { from: "user" }); @@ -391,8 +342,9 @@ describe("addCompileCommand#targets", () => { }); it("should yield warning w/ --targets cli argument, known and unknown names", () => { + const testSystem = compileSystem().fileSystem; testSystem.writeFile("./websmith.config.json", '{ "targets": {"whatever": {}, "known": {}} }'); - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); target.getReporter().reportDiagnostic = jest.fn(); addCompileCommand(new Command(), target).parse(["--targets", "unknown, known"], { from: "user" }); @@ -405,8 +357,9 @@ describe("addCompileCommand#targets", () => { }); it("should yield warning w/ --targets cli argument, known name but missing addons for target", () => { + const testSystem = compileSystem().fileSystem; testSystem.writeFile("./websmith.config.json", '{ "targets": {"known": { "addons": ["missing"]}} }'); - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); target.getReporter().reportDiagnostic = jest.fn(); expect(testSystem.fileExists("./tsconfig.json")).toBe(true); @@ -416,11 +369,12 @@ describe("addCompileCommand#targets", () => { }); it("should yield warning w/ --targets cli argument, multiple known names but missing addons for targets", () => { + const testSystem = compileSystem().fileSystem; testSystem.writeFile( "./websmith.config.json", '{ "targets": {"zip": { "addons": ["missing1"]}, "zap": { "addons": ["missing2"]}, "zup": { "addons": ["missing3"]}} }' ); - const target = new Compiler(createOptions({}, new NoReporter()), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); target.getReporter().reportDiagnostic = jest.fn(); addCompileCommand(new Command(), target).parse(["--targets", "zip, zap, zup"], { from: "user" }); @@ -480,3 +434,14 @@ describe("hasInvalidTargets", () => { ).toBe(true); }); }); + +const createAddon = (testSystem: ts.System, path: string, code = "export const activate = () => {};", mock: object = { activate: jest.fn() }) => { + testSystem.writeFile(`./${path}.js`, code); + jest.mock( + `/${path}`, + () => { + return mock; + }, + { virtual: true } + ); +}; From c5641c590b79141a882528502d7c3027446da288 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 5 May 2024 14:28:09 +0200 Subject: [PATCH 35/52] R!! Removes initial files property from CompilationEnv This is a major change in the AddonRegistry's lifecycle. No files are loaded upfront, no addons are compiled and activated in its constructor. + Don't read files initially, start with empty file system + Don't compile addons initially --- packages/compiler/src/options.spec.ts | 18 ++++-- .../src/compiler/addons/AddonRegistry.spec.ts | 36 ++++++------ .../core/src/compiler/addons/AddonRegistry.ts | 58 ++++++++++--------- .../testing/src/compilation/environment.ts | 57 ++++++++++-------- packages/webpack/src/options.spec.ts | 14 ++++- 5 files changed, 109 insertions(+), 74 deletions(-) diff --git a/packages/compiler/src/options.spec.ts b/packages/compiler/src/options.spec.ts index 8f88dd8a..487207c8 100644 --- a/packages/compiler/src/options.spec.ts +++ b/packages/compiler/src/options.spec.ts @@ -4,7 +4,7 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { CompilerAddon, NoReporter } from "@quatico/websmith-core"; +import { NoReporter } from "@quatico/websmith-core"; import { compileSystem } from "@quatico/websmith-testing"; import { createOptions } from "./options"; @@ -49,9 +49,9 @@ describe("createOptions", () => { { virtual: true } ); - const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.getAvailableAddons(); + const actual = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.refresh().getAvailableAddons(); - expect(actual.map(it => it.getName())).toEqual(["addon-foo"]); + expect(actual.getNames()).toEqual(["addon-foo"]); }); it("should return debug path w/ debug true", () => { @@ -95,10 +95,9 @@ describe("createOptions", () => { { virtual: true } ); - const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).addons; + const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).addons.refresh(); expect(actual).toMatchObject({ - addons: ["one", "two"], availableAddons: new Map( Object.entries({ one: { @@ -107,6 +106,15 @@ describe("createOptions", () => { }, }) ), + options: { + addons: "one,two", + addonsDir: "/expected", + config: { + addons: ["one", "two"], + addonsDir: "/expected", + configFilePath: "/websmith.config.json", + }, + }, }); }); }); diff --git a/packages/core/src/compiler/addons/AddonRegistry.spec.ts b/packages/core/src/compiler/addons/AddonRegistry.spec.ts index aa9f0693..c4f7a58a 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.spec.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.spec.ts @@ -5,7 +5,7 @@ * --------------------------------------------------------------------------------------------- */ import { WarnMessage } from "@quatico/websmith-api"; -import ts, { sys } from "typescript"; +import ts from "typescript"; import { ReporterMock, compileSystem } from "../../../test"; import { AddonRegistry } from "./AddonRegistry"; @@ -21,7 +21,7 @@ describe("Ctor", () => { reporter.reportDiagnostic = jest.fn(); expect(system.directoryExists("./addons")).toBe(false); - new AddonRegistry({ addonsDir: "./addons", reporter, system }); + new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Addons directory "./addons" does not exist.')); }); @@ -46,7 +46,7 @@ describe("getAvailableAddons", () => { it("returns addons w/ single addon in addon directory", () => { createAddon("addons/expected/addon"); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); }); @@ -56,7 +56,7 @@ describe("getAvailableAddons", () => { createAddon("addons/two/addon"); createAddon("addons/three/addon"); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["one", "two", "three"]); }); @@ -65,7 +65,7 @@ describe("getAvailableAddons", () => { createAddon("addons/expected/addon"); createAddon("addons/invalid/addon", "export const whatever = () => {};", { whatever: jest.fn() }); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); }); @@ -73,7 +73,7 @@ describe("getAvailableAddons", () => { it("returns no addons w/ empty files in addon directory", () => { createAddon("addons/empty/addon", "", {}); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons()).toHaveLength(0); }); @@ -125,7 +125,7 @@ describe("refresh", () => { it("refreshes addons w/ new addons", () => { createAddon("addons/expected/addon"); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); @@ -139,7 +139,7 @@ describe("refresh", () => { it("refreshes addons w/o new addons", () => { createAddon("addons/expected/addon"); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); @@ -152,7 +152,7 @@ describe("refresh", () => { createAddon("addons/expected/addon"); createAddon("addons/removed/addon"); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["expected", "removed"]); @@ -166,7 +166,7 @@ describe("refresh", () => { it("refreshes addons w/ empty addons directory", () => { createAddon("addons/expected/addon"); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); @@ -248,7 +248,7 @@ describe("getMissingAddons", () => { it("returns missing addons w/ missing and available addons", () => { createAddon("target/expected/addon"); - const testObj = new AddonRegistry({ addons: "missing, expected", addonsDir: "./target", reporter, system }); + const testObj = new AddonRegistry({ addons: "missing, expected", addonsDir: "./target", reporter, system }).refresh(); // @ts-expect-error private property access expect(testObj.getMissingAddons()).toEqual(["missing"]); @@ -259,7 +259,7 @@ describe("reportMissingAddons", () => { it("reports missing addons directory", () => { reporter.reportDiagnostic = jest.fn(); - const testObj = new AddonRegistry({ addonsDir: "./expected", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./expected", reporter, system }).refresh(); // @ts-expect-error private property access testObj.reportMissingAddons(undefined, []); @@ -281,7 +281,7 @@ describe("reportMissingAddons", () => { createAddon("target/expected/addon"); reporter.reportDiagnostic = jest.fn(); - new AddonRegistry({ addonsDir: "./target", addons: "expected", reporter, system }).getAvailableAddons(); + new AddonRegistry({ addonsDir: "./target", addons: "expected", reporter, system }).refresh().getAvailableAddons(); expect(reporter.reportDiagnostic).not.toHaveBeenCalled(); }); @@ -310,7 +310,9 @@ describe("reportMissingAddons", () => { addonsDir: "./target", reporter, system, - }).getAvailableAddons("target"); + }) + .refresh() + .getAvailableAddons("target"); expect(reporter.reportDiagnostic).not.toHaveBeenCalled(); }); @@ -320,7 +322,7 @@ describe("findAddons", () => { it("finds addons w/ single addon in addons directory", () => { createAddon("addons/expected/addon"); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); }); @@ -330,7 +332,7 @@ describe("findAddons", () => { createAddon("addons/two/addon"); createAddon("addons/three/addon"); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["one", "two", "three"]); }); @@ -339,7 +341,7 @@ describe("findAddons", () => { createAddon("addons/expected/addon"); createAddon("addons/invalid/addon", "export const whatever = () => {};", { whatever: jest.fn() }); - const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }); + const testObj = new AddonRegistry({ addonsDir: "./addons", reporter, system }).refresh(); expect(testObj.getAvailableAddons().getNames()).toEqual(["expected"]); }); diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index b9b6ab1d..8d6ea156 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -24,7 +24,7 @@ export class AddonRegistry { constructor(options: AddonRegistryOptions) { this.options = options; - this.availableAddons = this.findAddons(); + this.availableAddons = new Map(); } public getAddonsDir(): string { @@ -36,9 +36,7 @@ export class AddonRegistry { const expectedNames = this.getExpectedAddons(target); const results = expectedNames.length > 0 - ? Object.entries(this.availableAddons) - .filter(([name]) => expectedNames.includes(name)) - .map(([, addon]) => addon) + ? [...this.availableAddons].filter(([name]) => expectedNames.includes(name)).map(([, addon]) => addon) : Array.from(this.availableAddons.values()); return Object.assign(results, { getNames: () => results.map(it => it.getName()) }); } @@ -100,31 +98,39 @@ export class AddonRegistry { .readDirectory(addonsDir, [".js", ".jsx"]) .filter(dirName => basename(dirName, extname(dirName)).toLocaleLowerCase() === "addon") .forEach(filePath => { - const addonName = filePath - .replace(path.sep + basename(filePath), "") - .split(path.sep) - .slice(-1)[0]; - if (addonName) { - if (map.has(addonName)) { - reporter.reportDiagnostic(new WarnMessage(`Duplicate addon name "${addonName}" in "${addonsDir}".`)); - } else { - const resolvedPath = system.resolvePath(filePath); - const importPath = extname(resolvedPath).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) - ? resolvedPath.replace(extname(resolvedPath), "") - : resolvedPath; - // eslint-disable-next-line @typescript-eslint/no-var-requires - const activator = require(importPath).activate; - if (activator) { - map.set(addonName, { getName: () => addonName, activate: activator }); - } else { - reporter.reportDiagnostic( - new WarnMessage(`No "activate" function found for addon "${addonName}" in "${addonsDir}".`) - ); - } - } + const addonName = getAddonName(filePath); + if (!addonName) { + return; + } + if (map.has(addonName)) { + reporter.reportDiagnostic(new WarnMessage(`Duplicate addon name "${addonName}" in "${addonsDir}".`)); + return; + } + const addon = createAddon(system, filePath, addonName); + if (addon.activate) { + map.set(addonName, addon); + } else { + reporter.reportDiagnostic(new WarnMessage(`No "activate" function found for addon "${addonName}" in "${addonsDir}".`)); } }); } return map; } } + +const createAddon = (system: ts.System, filePath: string, addonName: string) => { + const importPath = getImportPath(system, filePath); + // eslint-disable-next-line @typescript-eslint/no-var-requires + return { getName: () => addonName, activate: require(importPath).activate }; +}; + +const getImportPath = (system: ts.System, filePath: string) => { + const resolvedPath = system.resolvePath(filePath); + return extname(resolvedPath).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) ? resolvedPath.replace(extname(resolvedPath), "") : resolvedPath; +}; + +const getAddonName = (filePath: string) => + filePath + .replace(path.sep + basename(filePath), "") + .split(path.sep) + .slice(-1)[0]; diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index ac07f111..fb2b7733 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -27,7 +27,7 @@ export class CompilationEnv { private virtual: boolean; constructor(rootDir?: string, options?: CompilationOptions) { - const { virtual = true, compilerOptions = {}, useCaseSensitiveFileNames, files } = options ?? {}; + const { virtual = true, compilerOptions = {}, useCaseSensitiveFileNames } = options ?? {}; this.virtual = virtual; this.system = this.virtual ? createBrowserSystem(undefined, useCaseSensitiveFileNames) : ts.sys; this.rootDir = resolvePath(this.system, rootDir ?? DEFAULT_ROOT_DIR); @@ -39,6 +39,14 @@ export class CompilationEnv { } this.system.getCurrentDirectory = () => this.rootDir; + if (!this.system.directoryExists(this.buildDir)) { + this.system.createDirectory(this.buildDir); + } + + if (!this.system.directoryExists(outDir)) { + this.system.createDirectory(outDir); + } + this.compilerOptions = compileOptions(this.system, { buildDir: this.buildDir, config: { @@ -52,8 +60,10 @@ export class CompilationEnv { project: { configFilePath: `${this.rootDir}/tsconfig.json`, outDir }, ...compilerOptions, }); - this.addFiles(files); - this.compileAddons(this.compilerOptions.addons.getAddonsDir()); + + if (!this.system.directoryExists(this.getAddonsDir())) { + this.system.createDirectory(this.getAddonsDir()); + } } /** @@ -125,20 +135,7 @@ export class CompilationEnv { this.system.createDirectory(addonTargetPath); } if (isFiles(addonSource)) { - this.addFiles( - Object.entries(addonSource).reduce((acc: Record, [filePath, content]) => { - if (isAbsolute(filePath)) { - acc[filePath] = content; - } else { - if (filePath.includes(addonName)) { - acc[join(this.getAddonsDir(), filePath)] = content; - } else { - acc[join(addonTargetPath, filePath)] = content; - } - } - return acc; - }, {}) - ); + this.addFiles(this.resolveSourcePaths(addonName, addonSource, addonTargetPath)); } else { const addonsSourceDir = resolveProjectPath(this.system, this.rootDir, join(addonSource ?? DEFAULT_ADDONS_SOURCE_DIR, addonName)); const sourceFs = this.system.directoryExists(addonsSourceDir) ? this.system : ts.sys; @@ -259,6 +256,21 @@ export class CompilationEnv { return file ? projectFile(this.system, this.buildDir, file) : undefined; } + private resolveSourcePaths(addonName: string, addonFiles: Record, addonTargetPath: string): Record { + return Object.entries(addonFiles).reduce((acc: Record, [filePath, content]) => { + if (isAbsolute(filePath)) { + acc[filePath] = content; + } else { + if (filePath.includes(addonName)) { + acc[join(this.getAddonsDir(), filePath)] = content; + } else { + acc[join(addonTargetPath, filePath)] = content; + } + } + return acc; + }, {}); + } + private compileAddons(addonsDir: string) { const addonsToCompile = this.system .readDirectory(addonsDir) @@ -281,13 +293,13 @@ export class CompilationEnv { if (this.virtual) { this.system .readDirectory(addonsDir, [".js", ".jsx"]) - .filter(it => basename(it, extname(it)).toLocaleLowerCase() === "addon") - .map(it => this.system.resolvePath(it)) - .forEach(it => { + .filter(filePath => basename(filePath, extname(filePath)).toLocaleLowerCase() === "addon") + .map(resolvedPath => this.system.resolvePath(resolvedPath)) + .forEach(resolvedPath => { jest.mock( - extname(it).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) ? it.replace(extname(it), "") : it, + extname(resolvedPath).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) ? resolvedPath.replace(extname(resolvedPath), "") : resolvedPath, // FIXME: replace __dirname with the actual sourceDir of the addon - () => requireFromString(this.system.readFile(it)!, __dirname), + () => requireFromString(this.system.readFile(resolvedPath)!, __dirname), { virtual: true } ); }); @@ -325,7 +337,6 @@ export type CompilationResult = { export type CompilationOptions = { compilerOptions?: Partial; - files?: Record; useCaseSensitiveFileNames?: boolean; virtual?: boolean; }; diff --git a/packages/webpack/src/options.spec.ts b/packages/webpack/src/options.spec.ts index 0208e06e..77cdffec 100644 --- a/packages/webpack/src/options.spec.ts +++ b/packages/webpack/src/options.spec.ts @@ -46,7 +46,7 @@ describe("createOptions", () => { { virtual: true } ); - const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.getAvailableAddons(); + const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.refresh().getAvailableAddons(); expect(actual.map(it => it.getName())).toEqual(["addon-foo"]); }); @@ -88,10 +88,9 @@ describe("createOptions", () => { { virtual: true } ); - const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).addons; + const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).addons.refresh(); expect(actual).toMatchObject({ - addons: ["one", "two"], availableAddons: new Map( Object.entries({ one: { @@ -100,6 +99,15 @@ describe("createOptions", () => { }, }) ), + options: { + addons: "one,two", + addonsDir: "/expected", + config: { + addons: ["one", "two"], + addonsDir: "/expected", + configFilePath: "/websmith.config.json", + }, + }, }); }); }); From f10ecf4fc426d925d5e928e96effab28b7824411 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 5 May 2024 14:33:26 +0200 Subject: [PATCH 36/52] R Adds project files in tests explicitly and and refresh the AddonRegistry --- packages/core/src/compiler/Compiler.ts | 1 + .../src/compilation/environment.spec.ts | 33 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/core/src/compiler/Compiler.ts b/packages/core/src/compiler/Compiler.ts index fed69064..09d795c0 100644 --- a/packages/core/src/compiler/Compiler.ts +++ b/packages/core/src/compiler/Compiler.ts @@ -82,6 +82,7 @@ export class Compiler { console.debug = () => undefined; console.log = () => undefined; } + this.options.addons?.refresh(); return this; } diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index 2d645b67..73bc4c58 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -80,7 +80,7 @@ describe("compilationEnv#addons", () => { const testObj = compilationEnv("/target"); expect(testObj.getAddonsDir()).toBe("/target/addons"); - expect(testObj.getActiveAddons()).toEqual([]); + expect(testObj.getActiveAddons()).toHaveLength(0); }); it("should yield addon with valid addon source", () => { @@ -307,11 +307,9 @@ describe("compilationEnv#compiled", () => { }); it("should yield no compiled files with existing project but no compile", () => { - const testObj = compilationEnv("/target", { - files: { - "index.ts": `export * from './target';`, - "target.ts": `export class Target {}`, - }, + const testObj = compilationEnv("/target").addProjectFromSource({ + "index.ts": `export * from './target';`, + "target.ts": `export class Target {}`, }); const actual = testObj.getCompiledFiles(); @@ -329,12 +327,12 @@ describe("compilationEnv#compiled", () => { }); it("should yield compiled files with existing project and compile", () => { - const testObj = compilationEnv("/target", { - files: { + const testObj = compilationEnv("/target") + .addProjectFromSource({ "index.ts": `export * from './target';`, "target.ts": `export class Target {}`, - }, - }).compile(); + }) + .compile(); expect(testObj.getCompiledFiles().getPaths()).toEqual(["/target/dist/index.js", "/target/dist/target.js"]); expect(testObj.hasEmitSkipped()).toBe(false); @@ -343,12 +341,12 @@ describe("compilationEnv#compiled", () => { }); it("should yield compiled contents with existing project and compile", () => { - const testObj = compilationEnv("/target", { - files: { + const testObj = compilationEnv("/target") + .addProjectFromSource({ "index.ts": `export * from './target';`, "target.ts": `export class Target {}`, - }, - }).compile(); + }) + .compile(); expect(testObj.getCompiledFile("/target/dist/index.js")!.getContent()).toBe(`export * from './target';\n`); expect(testObj.getCompiledFile("/target/dist/target.js")!.getContent()).toBe(`export class Target {\n}\n`); @@ -382,11 +380,12 @@ describe("compilationEnv#compiled", () => { it("should yield compilation errors with illegal project files", () => { const testObj = compilationEnv("/target", { compilerOptions: { project: { noEmitOnError: true } }, - files: { + }) + .addProjectFromSource({ "index.ts": `export * from './target';`, "target.ts": `export ILLEGAL Target {};`, - }, - }).compile(); + }) + .compile(); expect(testObj.getFailureReport("target.ts")).toMatchInlineSnapshot(` "src/index.ts(1,15): error TS2306: File '/target/src/target.ts' is not a module. From 9d63f58de813c6def94d1e286214615e4e592fdd Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 5 May 2024 23:14:33 +0200 Subject: [PATCH 37/52] R!! Removes the AddonRegistry from the CompilerOptions + Move AddonRegistry into the compiler as class property and provide a separate config parameter + Extend compile-system to configure and provide AddonRegistry separately + Remove addons from CompilerArguments --- packages/compiler/src/CompilerArguments.ts | 2 - packages/compiler/src/command.spec.ts | 193 +++++++++++------- packages/compiler/src/command.ts | 35 +++- packages/compiler/src/find-config.spec.ts | 16 +- packages/compiler/src/options.spec.ts | 36 ++-- packages/compiler/src/options.ts | 18 +- packages/core/src/compiler/Compiler.ts | 13 +- packages/core/src/compiler/CompilerOptions.ts | 6 +- .../src/compiler/addons/AddonRegistry.spec.ts | 14 +- .../core/src/compiler/addons/AddonRegistry.ts | 32 ++- .../core/src/compiler/addons/CompilerAddon.ts | 2 + .../src/compiler/config/resolve-targets.ts | 14 +- .../testing/src/compilation/environment.ts | 89 +++++--- packages/testing/src/compile-options.spec.ts | 1 - packages/testing/src/compile-options.ts | 5 +- packages/testing/src/compile-system.ts | 24 ++- packages/webpack/src/TsCompiler.ts | 13 +- packages/webpack/src/options.spec.ts | 44 ++-- packages/webpack/src/options.ts | 10 +- 19 files changed, 327 insertions(+), 240 deletions(-) diff --git a/packages/compiler/src/CompilerArguments.ts b/packages/compiler/src/CompilerArguments.ts index 8979c025..ce8b2e01 100644 --- a/packages/compiler/src/CompilerArguments.ts +++ b/packages/compiler/src/CompilerArguments.ts @@ -5,8 +5,6 @@ * --------------------------------------------------------------------------------------------- */ export interface CompilerArguments { - addons?: string; - addonsDir?: string; buildDir?: string; config?: string; debug?: boolean; diff --git a/packages/compiler/src/command.spec.ts b/packages/compiler/src/command.spec.ts index ff6254ee..2d1006e6 100644 --- a/packages/compiler/src/command.spec.ts +++ b/packages/compiler/src/command.spec.ts @@ -44,14 +44,14 @@ describe("addCompileCommand", () => { }); it("should yield default options w/o config and w/o CLI arguments", () => { - const testSystem = compileSystem().fileSystem; - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); + const { fileSystem: testSystem, addons } = compileSystem(); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem, addons); addCompileCommand(new Command(), target).parse([], { from: "user" }); const actual = target.getOptions(); - expect(actual.addons).toEqual( + expect(addons).toEqual( expect.objectContaining({ availableAddons: new Map(), }) @@ -102,7 +102,7 @@ describe("addCompileCommand", () => { }); it("should yield config option w/ --config cli argument", () => { - const testSystem = compileSystem({ "./expected/websmith.config.json": "{}" }).fileSystem; + const testSystem = compileSystem({ files: { "./expected/websmith.config.json": "{}" } }).fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--config", "./expected/websmith.config.json"], { from: "user" }); @@ -111,7 +111,7 @@ describe("addCompileCommand", () => { }); it("should yield project option w/ --project cli argument", () => { - const testSystem = compileSystem({ "./expected/tsconfig.json": "{}" }).fileSystem; + const testSystem = compileSystem({ files: { "./expected/tsconfig.json": "{}" } }).fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--project", "expected/tsconfig.json"], { from: "user" }); @@ -148,7 +148,7 @@ describe("addCompileCommand", () => { }); it("should yield transpileOnly option w/ --transpileOnly cli argument", () => { - const testSystem = compileSystem({ "./expected/tsconfig.json": "{}" }).fileSystem; + const testSystem = compileSystem({ files: { "./expected/tsconfig.json": "{}" } }).fileSystem; const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); addCompileCommand(new Command(), target).parse(["--transpileOnly"], { from: "user" }); @@ -196,92 +196,102 @@ describe("addCompileCommand", () => { describe("addCompileCommand#addons", () => { it("should yield warning w/ --addonsDir cli argument to non-existing path", () => { - const testSystem = compileSystem().fileSystem; - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); - target.getReporter().reportDiagnostic = jest.fn(); + const target = new NoReporter(); + target.reportDiagnostic = jest.fn(); + const { fileSystem: testSystem, addons } = compileSystem({ reporter: target }); + const compiler = new Compiler(createOptions({}, target, testSystem), testSystem, addons); - addCompileCommand(new Command(), target).parse(["--addonsDir", "./unknown"], { from: "user" }); + addCompileCommand(new Command(), compiler).parse(["--addonsDir", "./unknown"], { from: "user" }); - expect(target.getReporter().reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Addons directory "/unknown" does not exist.')); + expect(target.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Addons directory "./unknown" does not exist.')); }); it("should yield options addons w/ --addons cli argument and existing addon", () => { - const testSystem = compileSystem().fileSystem; + const { fileSystem: testSystem, addons } = compileSystem(); createAddon(testSystem, "addons/expected/addon"); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem, addons); addCompileCommand(new Command(), target).parse(["--addons", "expected"], { from: "user" }); - expect(target.getOptions().addons.refresh().getAvailableAddons().getNames()).toEqual(["expected"]); + expect(addons.refresh().getAvailableAddons().getNames()).toEqual(["expected"]); }); it("should yield options addons w/ --addons cli argument and multiple existing addons", () => { - const testSystem = compileSystem().fileSystem; + const { fileSystem: testSystem, addons } = compileSystem(); createAddon(testSystem, "addons/zip/addon"); createAddon(testSystem, "addons/zap/addon"); createAddon(testSystem, "addons/zup/addon"); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem, addons); addCompileCommand(new Command(), target).parse(["--addons", "zip, zap, zup"], { from: "user" }); - expect(target.getOptions().addons.refresh().getAvailableAddons().getNames()).toEqual(["zip", "zap", "zup"]); + expect(addons.refresh().getAvailableAddons().getNames()).toEqual(["zip", "zap", "zup"]); }); it("should yield empty options addons w/ --addons cli argument and non-existing addon", () => { - const testSystem = compileSystem().fileSystem; - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); + const { fileSystem: testSystem, addons } = compileSystem(); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem, addons); addCompileCommand(new Command(), target).parse(["--addons", "unknown"], { from: "user" }); - expect(target.getOptions().addons.getAvailableAddons()).toHaveLength(0); + expect(addons.getAvailableAddons()).toHaveLength(0); }); it("should not yield non-existing options addons w/ --addons cli argument, existing and non-existing addons", () => { - const testSystem = compileSystem().fileSystem; + const { fileSystem: testSystem, addons } = compileSystem(); createAddon(testSystem, "addons/expected/addon"); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem, addons); addCompileCommand(new Command(), target).parse(["--addons", "unknown, expected"], { from: "user" }); - expect(target.getOptions().addons.refresh().getAvailableAddons().getNames()).toEqual(["expected"]); + expect(addons.refresh().getAvailableAddons().getNames()).toEqual(["expected"]); }); it("should yield warning w/ --addons cli argument and non-existing addon name", () => { - const testSystem = compileSystem().fileSystem; - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); - target.getReporter().reportDiagnostic = jest.fn(); + const target = new NoReporter(); + target.reportDiagnostic = jest.fn(); + const { fileSystem: testSystem, addons } = compileSystem({ reporter: target }); + const compiler = new Compiler(createOptions({}, target, testSystem), testSystem, addons); - addCompileCommand(new Command(), target).parse(["--addons", "unknown"], { from: "user" }); + addCompileCommand(new Command(), compiler).parse(["--addons", "unknown"], { from: "user" }); - expect(target.getReporter().reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons: "unknown".')); + expect(target.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons: "unknown".')); }); it("should yield warning w/ --addons cli argument, existing and non-existing addons", () => { - const testSystem = compileSystem({ "./websmith.config.json": "{}" }).fileSystem; + const target = new NoReporter(); + target.reportDiagnostic = jest.fn(); + const { fileSystem: testSystem, addons } = compileSystem({ files: { "./websmith.config.json": "{}" }, reporter: target }); createAddon(testSystem, "addons/existing/addon"); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); - target.getReporter().reportDiagnostic = jest.fn(); + const compiler = new Compiler(createOptions({}, target, testSystem), testSystem, addons); - addCompileCommand(new Command(), target).parse(["--addons", "existing, unknown"], { from: "user" }); + addCompileCommand(new Command(), compiler).parse(["--addons", "existing, unknown"], { from: "user" }); - expect(target.getReporter().reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons: "unknown".')); + expect(target.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons: "unknown".')); }); it("should yield addonsDir and addons from compiler config w/o any cli argument", () => { - const testSystem = compileSystem().fileSystem; + const { fileSystem: testSystem, addons } = compileSystem({ + files: { "websmith.config.json": '{ "addons":["one", "two"], "addonsDir":"./expected" }' }, + }); createAddon(testSystem, "expected/one/addon"); - testSystem.writeFile("websmith.config.json", '{ "addons":["one", "two"], "addonsDir":"./expected" }'); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); + const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem, addons); addCompileCommand(new Command(), target).parse([], { from: "user" }); - expect(target.getOptions().addons).toMatchObject({ + expect(addons).toMatchObject({ options: { addons: "one,two", addonsDir: "/expected", - config: { addons: ["one", "two"], addonsDir: "/expected", configFilePath: "/websmith.config.json" }, }, - availableAddons: {}, + availableAddons: new Map( + Object.entries({ + one: { + activate: expect.any(Function), + getName: expect.any(Function), + }, + }) + ), }); }); }); @@ -306,13 +316,15 @@ describe("addCompileCommand#targets", () => { }); it("should yield warning w/ --targets cli argument and unknown name", () => { - const testSystem = compileSystem().fileSystem; - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); - target.getReporter().reportDiagnostic = jest.fn(); + const target = new NoReporter(); + target.reportDiagnostic = jest.fn(); + const { fileSystem: testSystem, addons } = compileSystem({ reporter: target }); - addCompileCommand(new Command(), target).parse(["--targets", "unknown"], { from: "user" }); + addCompileCommand(new Command(), new Compiler(createOptions({}, target, testSystem), testSystem, addons)).parse(["--targets", "unknown"], { + from: "user", + }); - expect(target.getReporter().reportDiagnostic).toHaveBeenCalledWith( + expect(target.reportDiagnostic).toHaveBeenCalledWith( new WarnMessage( 'Custom target configuration "unknown" found, but no target provided.\n\tSome custom addons may not be applied during compilation.' ) @@ -320,36 +332,50 @@ describe("addCompileCommand#targets", () => { }); it("should not yield any warning w/ --targets cli argument and known names", () => { - const testSystem = compileSystem().fileSystem; - testSystem.writeFile("./websmith.config.json", '{ "targets": {"expected": {}} }'); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); - target.getReporter().reportDiagnostic = jest.fn(); + const target = new NoReporter(); + target.reportDiagnostic = jest.fn(); + const { fileSystem: testSystem, addons } = compileSystem({ + files: { "./websmith.config.json": '{ "targets": {"expected": {}} }' }, + reporter: target, + }); - addCompileCommand(new Command(), target).parse(["--targets", "expected"], { from: "user" }); + addCompileCommand(new Command(), new Compiler(createOptions({}, target, testSystem), testSystem, addons)).parse(["--targets", "expected"], { + from: "user", + }); - expect(target.getReporter().reportDiagnostic).not.toHaveBeenCalled(); + expect(target.reportDiagnostic).not.toHaveBeenCalled(); }); it("should not yield any warning w/ --targets cli argument and multiple known names", () => { - const testSystem = compileSystem().fileSystem; - testSystem.writeFile("./websmith.config.json", '{ "targets": {"zip": {}, "zap": {}, "zup": {}} }'); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); - target.getReporter().reportDiagnostic = jest.fn(); + const target = new NoReporter(); + target.reportDiagnostic = jest.fn(); + const { fileSystem: testSystem, addons } = compileSystem({ + files: { "./websmith.config.json": '{ "targets": {"zip": {}, "zap": {}, "zup": {}} }' }, + reporter: target, + }); - addCompileCommand(new Command(), target).parse(["--targets", "zip, zap, zup"], { from: "user" }); + addCompileCommand(new Command(), new Compiler(createOptions({}, target, testSystem), testSystem, addons)).parse( + ["--targets", "zip, zap, zup"], + { from: "user" } + ); - expect(target.getReporter().reportDiagnostic).not.toHaveBeenCalled(); + expect(target.reportDiagnostic).not.toHaveBeenCalled(); }); it("should yield warning w/ --targets cli argument, known and unknown names", () => { - const testSystem = compileSystem().fileSystem; - testSystem.writeFile("./websmith.config.json", '{ "targets": {"whatever": {}, "known": {}} }'); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); - target.getReporter().reportDiagnostic = jest.fn(); + const target = new NoReporter(); + target.reportDiagnostic = jest.fn(); + const { fileSystem: testSystem, addons } = compileSystem({ + files: { "./websmith.config.json": '{ "targets": {"whatever": {}, "known": {}} }' }, + reporter: target, + }); - addCompileCommand(new Command(), target).parse(["--targets", "unknown, known"], { from: "user" }); + addCompileCommand(new Command(), new Compiler(createOptions({}, target, testSystem), testSystem, addons)).parse( + ["--targets", "unknown, known"], + { from: "user" } + ); - expect(target.getReporter().reportDiagnostic).toHaveBeenCalledWith( + expect(target.reportDiagnostic).toHaveBeenCalledWith( new WarnMessage( 'Custom target configuration "unknown,known" found, but no target provided.\n\tSome custom addons may not be applied during compilation.' ) @@ -357,31 +383,40 @@ describe("addCompileCommand#targets", () => { }); it("should yield warning w/ --targets cli argument, known name but missing addons for target", () => { - const testSystem = compileSystem().fileSystem; - testSystem.writeFile("./websmith.config.json", '{ "targets": {"known": { "addons": ["missing"]}} }'); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); - target.getReporter().reportDiagnostic = jest.fn(); + const target = new NoReporter(); + target.reportDiagnostic = jest.fn(); + const { fileSystem: testSystem, addons } = compileSystem({ + files: { "./websmith.config.json": '{ "targets": {"known": { "addons": ["missing"]}} }' }, + reporter: target, + }); expect(testSystem.fileExists("./tsconfig.json")).toBe(true); - addCompileCommand(new Command(), target).parse(["--targets", "known"], { from: "user" }); + addCompileCommand(new Command(), new Compiler(createOptions({}, target, testSystem), testSystem, addons)).parse(["--targets", "known"], { + from: "user", + }); - expect(target.getReporter().reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "known": "missing".')); + expect(target.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "known": "missing".')); }); it("should yield warning w/ --targets cli argument, multiple known names but missing addons for targets", () => { - const testSystem = compileSystem().fileSystem; - testSystem.writeFile( - "./websmith.config.json", - '{ "targets": {"zip": { "addons": ["missing1"]}, "zap": { "addons": ["missing2"]}, "zup": { "addons": ["missing3"]}} }' - ); - const target = new Compiler(createOptions({}, new NoReporter(), testSystem), testSystem); - target.getReporter().reportDiagnostic = jest.fn(); + const target = new NoReporter(); + target.reportDiagnostic = jest.fn(); + const { fileSystem: testSystem, addons } = compileSystem({ + files: { + "./websmith.config.json": + '{ "targets": {"zip": { "addons": ["missing1"]}, "zap": { "addons": ["missing2"]}, "zup": { "addons": ["missing3"]}} }', + }, + reporter: target, + }); - addCompileCommand(new Command(), target).parse(["--targets", "zip, zap, zup"], { from: "user" }); + addCompileCommand(new Command(), new Compiler(createOptions({}, target, testSystem), testSystem, addons)).parse( + ["--targets", "zip, zap, zup"], + { from: "user" } + ); - expect(target.getReporter().reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "zip": "missing1".')); - expect(target.getReporter().reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "zap": "missing2".')); - expect(target.getReporter().reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "zup": "missing3".')); + expect(target.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "zip": "missing1".')); + expect(target.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "zap": "missing2".')); + expect(target.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons for target "zup": "missing3".')); }); }); diff --git a/packages/compiler/src/command.ts b/packages/compiler/src/command.ts index 6a60356f..ab8e7c32 100644 --- a/packages/compiler/src/command.ts +++ b/packages/compiler/src/command.ts @@ -5,7 +5,7 @@ * --------------------------------------------------------------------------------------------- */ import { WarnMessage } from "@quatico/websmith-api"; -import { CompilationConfig, Compiler, DefaultReporter } from "@quatico/websmith-core"; +import { AddonRegistry, CompilationConfig, Compiler, DefaultReporter, resolveCompilationConfig } from "@quatico/websmith-core"; import { Command, program } from "commander"; import parseArgs from "minimist"; import { compileSystem } from "./compiler-system"; @@ -46,13 +46,15 @@ export const addCompileCommand = (parent = program, compiler?: Compiler): Comman .action((args: CompilerArguments, command: Command) => { // TODO: Add files from CLI argument const system = compiler?.getSystem() ?? compileSystem(); - const options = createOptions(args, compiler?.getReporter() ?? new DefaultReporter(system), system); + const reporter = compiler?.getReporter() ?? new DefaultReporter(system); + const options = createOptions(args, reporter, system); + const compilationConfig = resolveCompilationConfig(args.config ?? "./websmith.config.json", reporter, system); const unknownArgs = (command?.args ?? []).filter(arg => !command.getOptionValueSource(arg)); if (unknownArgs?.length > 0) { options.additionalArguments = parseUnknownArguments(unknownArgs); } if (hasInvalidTargets(options.targets, options.config)) { - options.reporter.reportDiagnostic( + reporter.reportDiagnostic( new WarnMessage( `Custom target configuration "${options.targets.join(",")}" found, but no target provided.\n` + `\tSome custom addons may not be applied during compilation.` @@ -61,9 +63,32 @@ export const addCompileCommand = (parent = program, compiler?: Compiler): Comman } if (compiler === undefined) { - compiler = new Compiler(options, system); + let addons; + if (command.opts().addonsDir || command.opts().addons) { + addons = new AddonRegistry({ + addons: command.opts().addons ?? compilationConfig?.addons?.join(","), + addonsDir: + command.opts().addonsDir && command.opts().addonsDir !== "./addons" + ? command.opts().addonsDir + : compilationConfig?.addonsDir ?? "./addons", + targets: options.config?.targets, + reporter, + system, + }); + } + compiler = new Compiler(options, system, addons); } else { - compiler.setOptions(options); + compiler + .setOptions(options) + .getAddonRegistry() + ?.setOptions({ + addons: command.opts().addons ?? compilationConfig?.addons?.join(","), + addonsDir: + command.opts().addonsDir && command.opts().addonsDir !== "./addons" + ? command.opts().addonsDir + : compilationConfig?.addonsDir ?? "./addons", + targets: options.config?.targets, + }); } if (args.watch) { diff --git a/packages/compiler/src/find-config.spec.ts b/packages/compiler/src/find-config.spec.ts index 22b258f1..e2e09651 100644 --- a/packages/compiler/src/find-config.spec.ts +++ b/packages/compiler/src/find-config.spec.ts @@ -9,12 +9,12 @@ import { findConfigFile, findSassConfig } from "./find-config"; describe("findConfigFile", () => { it("returns file name with path to existing file", () => { - const { fileSystem: target } = compileSystem( - { - "tsconfig.json": JSON.stringify({}), + const { fileSystem: target } = compileSystem({ + files: { + "tsconfig.json": "{}", }, - { withDefaultFiles: false } - ); + withDefaultFiles: false, + }); const actual = findConfigFile("./", target); @@ -22,7 +22,7 @@ describe("findConfigFile", () => { }); it("throws error with no existing config file", () => { - const { fileSystem: target } = compileSystem({}, { withDefaultFiles: false }); + const { fileSystem: target } = compileSystem({ withDefaultFiles: false }); expect(() => findConfigFile("./", target)).toThrow("Could not find a valid 'tsconfig.json'."); }); @@ -30,7 +30,7 @@ describe("findConfigFile", () => { describe("findSassConfig", () => { it("returns file name with path to existing file", () => { - const { fileSystem: target } = compileSystem({ "sass.config.js": `{}` }); + const { fileSystem: target } = compileSystem({ files: { "sass.config.js": `{}` } }); const actual = findSassConfig("sass.config.js", target); @@ -38,7 +38,7 @@ describe("findSassConfig", () => { }); it("returns file name with path to custom existing file", () => { - const { fileSystem: target } = compileSystem({ "expected.js": `{}` }); + const { fileSystem: target } = compileSystem({ files: { "expected.js": `{}` } }); const actual = findSassConfig("expected.js", target); diff --git a/packages/compiler/src/options.spec.ts b/packages/compiler/src/options.spec.ts index 487207c8..1b920d48 100644 --- a/packages/compiler/src/options.spec.ts +++ b/packages/compiler/src/options.spec.ts @@ -24,7 +24,9 @@ describe("createOptions", () => { it("should return project config w/ custom but empty tsconfig.json", () => { const { fileSystem: target } = compileSystem({ - "./expected/tsconfig.json": "{}", + files: { + "./expected/tsconfig.json": "{}", + }, }); const actual = createOptions({ project: "./expected/tsconfig.json" }, new NoReporter(), target).project; @@ -38,8 +40,11 @@ describe("createOptions", () => { }); it("should return expected path w/ custom addons directory", () => { - const { fileSystem: target } = compileSystem({ - "./expected/addon-foo/addon.js": "export const activate = () => {};", + const { addons } = compileSystem({ + files: { + "./expected/addon-foo/addon.js": "export const activate = () => {};", + }, + addonConfig: { addonsDir: "./expected" }, }); jest.mock( "/expected/addon-foo/addon", @@ -49,7 +54,7 @@ describe("createOptions", () => { { virtual: true } ); - const actual = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.refresh().getAvailableAddons(); + const actual = addons.refresh().getAvailableAddons(); expect(actual.getNames()).toEqual(["addon-foo"]); }); @@ -71,7 +76,9 @@ describe("createOptions", () => { it("should return config w/ valid compiler config json", () => { const { fileSystem: target } = compileSystem({ - "websmith.config.json": '{ "targets": { "whatever": { "addons": [ "one", "two", "three" ], "writeFile": true } } }', + files: { + "websmith.config.json": '{ "targets": { "whatever": { "addons": [ "one", "two", "three" ], "writeFile": true } } }', + }, }); const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).config; @@ -83,9 +90,11 @@ describe("createOptions", () => { }); it("should return config w/ valid addonsDir, addons in compiler config json", () => { - const { fileSystem: target } = compileSystem({ - "./expected/one/addon.js": "export const activate = () => {};", - "./websmith.config.json": '{ "addons":["one", "two"], "addonsDir":"./expected" }', + const { addons } = compileSystem({ + files: { + "./expected/one/addon.js": "export const activate = () => {};", + "./websmith.config.json": '{ "addons":["one", "two"], "addonsDir":"./expected" }', + }, }); jest.mock( "/expected/one/addon", @@ -95,7 +104,7 @@ describe("createOptions", () => { { virtual: true } ); - const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).addons.refresh(); + const actual = addons.refresh(); expect(actual).toMatchObject({ availableAddons: new Map( @@ -107,13 +116,8 @@ describe("createOptions", () => { }) ), options: { - addons: "one,two", - addonsDir: "/expected", - config: { - addons: ["one", "two"], - addonsDir: "/expected", - configFilePath: "/websmith.config.json", - }, + addonsDir: "./expected", + addons: ["one", "two"], }, }); }); diff --git a/packages/compiler/src/options.ts b/packages/compiler/src/options.ts index df2055d0..15f09e14 100644 --- a/packages/compiler/src/options.ts +++ b/packages/compiler/src/options.ts @@ -5,7 +5,6 @@ * --------------------------------------------------------------------------------------------- */ import { - AddonRegistry, CompilerOptions, NoReporter, resolveCompilationConfig, @@ -13,12 +12,11 @@ import { resolveProjectConfig as resolveTsConfig, updateCompilerOptions, } from "@quatico/websmith-core"; -import { dirname, join } from "path"; +import { dirname } from "path"; import ts from "typescript"; import { CompilerArguments } from "./CompilerArguments"; const DEFAULTS = { - addonsDir: "./addons", config: "./websmith.config.json", debug: false, outDir: "./lib", @@ -47,21 +45,7 @@ export const createOptions = (args: CompilerArguments, reporter = new NoReporter } } - args = { - ...args, - ...(args.addonsDir && - projectDirectory && - args.addonsDir !== DEFAULTS.addonsDir && { addonsDir: system.resolvePath(join(projectDirectory, args.addonsDir)) }), - }; - return { - addons: new AddonRegistry({ - addons: args.addons ?? compilationConfig?.addons?.join(","), - addonsDir: args.addonsDir && args.addonsDir !== DEFAULTS.addonsDir ? args.addonsDir : compilationConfig?.addonsDir ?? DEFAULTS.addonsDir, - config: compilationConfig, - reporter, - system, - }), buildDir: args.buildDir ?? system.getCurrentDirectory(), config: compilationConfig, debug: args.debug ?? DEFAULTS.debug, diff --git a/packages/core/src/compiler/Compiler.ts b/packages/core/src/compiler/Compiler.ts index 09d795c0..931a8b53 100644 --- a/packages/core/src/compiler/Compiler.ts +++ b/packages/core/src/compiler/Compiler.ts @@ -15,6 +15,7 @@ import { CompilationContext, CompilationHost, createSharedHost } from "./compila import { CompilerOptions } from "./CompilerOptions"; import { CompilationConfig } from "./config"; import { DefaultReporter } from "./DefaultReporter"; +import { AddonRegistry } from "./addons"; export type CompileFragment = { version: number; @@ -42,10 +43,12 @@ export class Compiler { private system!: ts.System; private dependencyCallback?: (filePath: string) => void; private fileWatchers: ts.FileWatcher[] = []; + private addons?: AddonRegistry; - constructor(options: CompilerOptions, system?: ts.System, dependencyCallback?: (filePath: string) => void) { + constructor(options: CompilerOptions, system?: ts.System, addons?: AddonRegistry, dependencyCallback?: (filePath: string) => void) { this.version = 0; this.contextMap = new Map(); + this.addons = addons; this.system = system ?? createSystem(); this.setOptions(options); this.dependencyCallback = dependencyCallback; @@ -63,6 +66,10 @@ export class Compiler { return this.reporter; } + public getAddonRegistry(): AddonRegistry | undefined { + return this.addons; + } + public getOptions(): CompilerOptions { return this.options; } @@ -74,6 +81,7 @@ export class Compiler { } this.reporter = options.reporter ?? new DefaultReporter(this.system); + this.compilationHost = new CompilationHost(createSharedHost(this.system) as ts.LanguageServiceHost); this.langService = ts.createLanguageService(this.compilationHost, ts.createDocumentRegistry()); this.program = this.langService.getProgram(); @@ -82,7 +90,6 @@ export class Compiler { console.debug = () => undefined; console.log = () => undefined; } - this.options.addons?.refresh(); return this; } @@ -188,7 +195,7 @@ export class Compiler { } const ctx = this.createCompilationContext(this.options, target, this.dependencyCallback); - this.options.addons.getAvailableAddons(target).forEach(addon => { + this.addons?.getAvailableAddons(target).forEach(addon => { addon.activate(ctx); }); this.contextMap.set(target, ctx); diff --git a/packages/core/src/compiler/CompilerOptions.ts b/packages/core/src/compiler/CompilerOptions.ts index 640b52a5..f0c3aa5c 100644 --- a/packages/core/src/compiler/CompilerOptions.ts +++ b/packages/core/src/compiler/CompilerOptions.ts @@ -4,13 +4,11 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import ts from "typescript"; import { Reporter } from "@quatico/websmith-api"; -import { AddonRegistry } from "./addons"; -import { CompilationConfig } from "./config"; +import ts from "typescript"; +import type { CompilationConfig } from "./config"; export interface CompilerOptions { - addons: AddonRegistry; buildDir: string; config?: CompilationConfig; debug: boolean; diff --git a/packages/core/src/compiler/addons/AddonRegistry.spec.ts b/packages/core/src/compiler/addons/AddonRegistry.spec.ts index c4f7a58a..5b7487b3 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.spec.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.spec.ts @@ -83,8 +83,8 @@ describe("getAvailableAddons", () => { reporter.reportDiagnostic = jest.fn(); new AddonRegistry({ + addons: "does-not-exist", addonsDir: "./addons", - config: { addons: ["does-not-exist"], configFilePath: "" }, reporter, system, }).getAvailableAddons(); @@ -98,7 +98,7 @@ describe("getAvailableAddons", () => { new AddonRegistry({ addonsDir: "./addons", - config: { targets: { target: { addons: ["does-not-exist"] } }, configFilePath: "" }, + targets: { target: { addons: ["does-not-exist"] } }, reporter, system, }).getAvailableAddons("target"); @@ -195,7 +195,7 @@ describe("getExpectedAddons", () => { it("returns target addons w/ target", () => { const testObj = new AddonRegistry({ - config: { targets: { target: { addons: ["one", "two", "three"] } }, configFilePath: "" }, + targets: { target: { addons: ["one", "two", "three"] } }, addonsDir: "./empty", reporter, system, @@ -207,7 +207,7 @@ describe("getExpectedAddons", () => { it("returns empty w/ target and no addons", () => { const testObj = new AddonRegistry({ - config: { targets: { target: { addons: [] } }, configFilePath: "" }, + targets: { target: { addons: [] } }, addonsDir: "./empty", reporter, system, @@ -219,7 +219,7 @@ describe("getExpectedAddons", () => { it("returns empty w/ target and no target", () => { const testObj = new AddonRegistry({ - config: { targets: { target: { addons: ["one", "two", "three"] } }, configFilePath: "" }, + targets: { target: { addons: ["one", "two", "three"] } }, addonsDir: "./empty", reporter, system, @@ -291,7 +291,7 @@ describe("reportMissingAddons", () => { reporter.reportDiagnostic = jest.fn(); new AddonRegistry({ - config: { targets: { target: { addons: ["missing"] } }, configFilePath: "" }, + targets: { target: { addons: ["missing"] } }, addonsDir: "./target", reporter, system, @@ -306,7 +306,7 @@ describe("reportMissingAddons", () => { reporter.reportDiagnostic = jest.fn(); new AddonRegistry({ - config: { targets: { target: { addons: ["expected"] } }, configFilePath: "" }, + targets: { target: { addons: ["expected"] } }, addonsDir: "./target", reporter, system, diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index 8d6ea156..e5b24223 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -4,16 +4,15 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { Reporter, WarnMessage } from "@quatico/websmith-api"; +import { Reporter, WarnMessage, type TargetConfig } from "@quatico/websmith-api"; import path, { basename, extname } from "path"; import ts from "typescript"; -import { CompilationConfig } from "../config"; -import type { CompilerAddon, CompilerAddons } from "./CompilerAddon"; +import { compilerAddons, type CompilerAddon, type CompilerAddons } from "./CompilerAddon"; export type AddonRegistryOptions = { addons?: string; addonsDir: string; - config?: CompilationConfig; + targets?: Record; reporter: Reporter; system: ts.System; }; @@ -23,8 +22,13 @@ export class AddonRegistry { private options: AddonRegistryOptions; constructor(options: AddonRegistryOptions) { - this.options = options; this.availableAddons = new Map(); + this.options = { ...options }; + } + + setOptions(options: Partial): this { + this.options = { ...this.options, ...options }; + return this.refresh(); } public getAddonsDir(): string { @@ -38,7 +42,7 @@ export class AddonRegistry { expectedNames.length > 0 ? [...this.availableAddons].filter(([name]) => expectedNames.includes(name)).map(([, addon]) => addon) : Array.from(this.availableAddons.values()); - return Object.assign(results, { getNames: () => results.map(it => it.getName()) }); + return compilerAddons(results); } public refresh(): this { @@ -47,26 +51,16 @@ export class AddonRegistry { } private getExpectedAddons(target?: string): string[] { - const { config, addons } = this.options; + const { targets = {}, addons } = this.options; const requestedAddons = addons ?.split(",") .map(it => it.trim()) .filter(it => it.length > 0) ?? []; - if (requestedAddons.length > 0) { - return requestedAddons; - } + const targetAddons = target ? targets[target]?.addons ?? [] : []; - if (config) { - if (target) { - const { targets = {} } = config; - return targets[target]?.addons ?? []; - } else { - return config.addons ?? []; - } - } - return []; + return [...new Set([...requestedAddons, ...targetAddons])]; } private getMissingAddons(target?: string): string[] { diff --git a/packages/core/src/compiler/addons/CompilerAddon.ts b/packages/core/src/compiler/addons/CompilerAddon.ts index 8f556659..20c3b4f8 100644 --- a/packages/core/src/compiler/addons/CompilerAddon.ts +++ b/packages/core/src/compiler/addons/CompilerAddon.ts @@ -17,3 +17,5 @@ export interface CompilerAddon { export type CompilerAddons = CompilerAddon[] & { getNames: () => string[]; }; + +export const compilerAddons = (addons: CompilerAddon[]): CompilerAddons => Object.assign(addons, { getNames: () => addons.map(it => it.getName()) }); diff --git a/packages/core/src/compiler/config/resolve-targets.ts b/packages/core/src/compiler/config/resolve-targets.ts index 43ea176d..cda59807 100644 --- a/packages/core/src/compiler/config/resolve-targets.ts +++ b/packages/core/src/compiler/config/resolve-targets.ts @@ -15,12 +15,14 @@ export const resolveTargets = (targets: string, config: CompilationConfig | unde .split(",") .map(it => it.trim()) .filter(it => it.length > 0); - const expectedTargets = Object.keys(config?.targets ?? {}); - const missingTargets = passedTargets.filter(cur => expectedTargets.length > 0 && !expectedTargets.includes(cur)); - if (missingTargets.length > 0) { - reporter.reportDiagnostic( - new WarnMessage(`Missing targets: The following targets are passed but not configured "${missingTargets.join(", ")}"`) - ); + if (passedTargets.length > 0 && passedTargets[0] !== "*") { + const configured = Object.keys(config?.targets ?? {}); + const missingTargets = passedTargets.filter(passed => configured[0] !== "*" && !configured.includes(passed)); + if (missingTargets.length > 0) { + reporter.reportDiagnostic( + new WarnMessage(`Missing targets: The following targets are passed but not configured "${missingTargets.join(", ")}"`) + ); + } } return passedTargets; }; diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index fb2b7733..55eae007 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -4,7 +4,17 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { AddonRegistry, Compiler, createBrowserSystem, type CompilerAddon, type CompilerOptions } from "@quatico/websmith-core"; +import { + AddonRegistry, + AddonRegistryOptions, + Compiler, + CompilerAddons, + DefaultReporter, + compilerAddons, + createBrowserSystem, + type CompilerAddon, + type CompilerOptions, +} from "@quatico/websmith-core"; import { rmSync } from "fs"; import { basename, dirname, extname, isAbsolute, join } from "path"; import requireFromString from "require-from-string"; @@ -25,8 +35,9 @@ export class CompilationEnv { private buildDir: string; private system: ts.System; private virtual: boolean; + private addons?: AddonRegistry; - constructor(rootDir?: string, options?: CompilationOptions) { + constructor(rootDir?: string, options?: CompilationOptions, addonsConfig?: AddonRegistryOptions) { const { virtual = true, compilerOptions = {}, useCaseSensitiveFileNames } = options ?? {}; this.virtual = virtual; this.system = this.virtual ? createBrowserSystem(undefined, useCaseSensitiveFileNames) : ts.sys; @@ -61,8 +72,16 @@ export class CompilationEnv { ...compilerOptions, }); - if (!this.system.directoryExists(this.getAddonsDir())) { - this.system.createDirectory(this.getAddonsDir()); + if (!addonsConfig) { + addonsConfig = { + addonsDir: join(this.rootDir, "./addons"), + reporter: new DefaultReporter(this.system), + system: this.system, + }; + } + this.addons = new AddonRegistry(addonsConfig); + if (!this.system.directoryExists(this.addons.getAddonsDir())) { + this.system.createDirectory(this.addons.getAddonsDir()); } } @@ -88,7 +107,7 @@ export class CompilationEnv { } public cleanUp(options: "project" | "addons" | "all" = "all"): this { - const target = options === "project" ? this.getProjectDir() : options === "addons" ? this.getAddonsDir() : this.rootDir; + const target = options === "project" ? this.getProjectDir() : options === "addons" && this.addons ? this.addons.getAddonsDir() : this.rootDir; if (this.system.directoryExists(target)) { if (this.isVirtual()) { this.system.readDirectory(target).forEach(it => this.system.deleteFile!(it)); @@ -104,19 +123,17 @@ export class CompilationEnv { * * @returns absolute path to the addons directory, defaults to `${this.rootDir}/addons` */ - public getAddonsDir(): string { - return this.getAddonRegistry().getAddonsDir(); + public getAddonsDir(): string | undefined { + return this.addons?.getAddonsDir(); } // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents public getActiveAddon(addonName: string): CompilerAddon | undefined { - return this.getAddonRegistry() - .getAvailableAddons() - .find((it: CompilerAddon) => it.getName() === addonName); + return this.addons?.getAvailableAddons().find((it: CompilerAddon) => it.getName() === addonName); } - public getActiveAddons(): CompilerAddon[] { - return this.getAddonRegistry().getAvailableAddons(); + public getActiveAddons(): CompilerAddons { + return this.addons?.getAvailableAddons() ?? compilerAddons([]); } /** @@ -129,34 +146,40 @@ export class CompilationEnv { * @returns this instance */ public addAddon(addonName: string, addonSource?: string | Record): this { - const addonTargetPath = join(this.getAddonsDir(), addonName); + if (!this.addons) { + return this; + } + const addonTargetPath = join(this.addons.getAddonsDir(), addonName); if (!this.system.directoryExists(addonTargetPath)) { this.system.createDirectory(addonTargetPath); } if (isFiles(addonSource)) { - this.addFiles(this.resolveSourcePaths(addonName, addonSource, addonTargetPath)); + this.addFiles(this.resolveAddonSourcePaths(addonName, addonSource, addonTargetPath)); } else { const addonsSourceDir = resolveProjectPath(this.system, this.rootDir, join(addonSource ?? DEFAULT_ADDONS_SOURCE_DIR, addonName)); const sourceFs = this.system.directoryExists(addonsSourceDir) ? this.system : ts.sys; copyDirectory({ system: sourceFs, path: addonsSourceDir, kind: "addons" }, { system: this.system, path: addonTargetPath }); } - this.compileAddons(this.getAddonRegistry().getAddonsDir()); - this.getAddonRegistry().refresh(); + if (this.addons) { + this.compileAddons(this.addons.getAddonsDir()); + this.addons.refresh(); + } return this; } public addAddons(addonNames: string[], addonsSourceDir?: string): this { - const addonsDir = this.getAddonsDir(); - const addonsSourceDirPath = resolveProjectPath(this.system, this.rootDir, addonsSourceDir ?? DEFAULT_ADDONS_SOURCE_DIR); - const sourceFs = this.system.directoryExists(addonsSourceDirPath) ? this.system : ts.sys; - addonNames.forEach(addon => { - copyDirectory({ system: sourceFs, path: join(addonsSourceDirPath, addon), kind: "addons" }, { system: this.system, path: addonsDir }); - }); - this.compileAddons(addonsDir); - this.getAddonRegistry().refresh(); - + if (this.addons) { + const addonsDir = this.addons.getAddonsDir(); + const addonsSourceDirPath = resolveProjectPath(this.system, this.rootDir, addonsSourceDir ?? DEFAULT_ADDONS_SOURCE_DIR); + const sourceFs = this.system.directoryExists(addonsSourceDirPath) ? this.system : ts.sys; + addonNames.forEach(addon => { + copyDirectory({ system: sourceFs, path: join(addonsSourceDirPath, addon), kind: "addons" }, { system: this.system, path: addonsDir }); + }); + this.compileAddons(addonsDir); + this.addons?.refresh(); + } return this; } @@ -216,7 +239,7 @@ export class CompilationEnv { } public compile(): this & CompilationResult { - const result = new Compiler(this.compilerOptions, this.system).compile(); + const result = new Compiler(this.compilerOptions, this.system, this.addons).compile(); // @ts-expect-error - method is not part of the original object this.getDiagnostics = () => result.diagnostics; // @ts-expect-error - method is not part of the original object @@ -256,13 +279,16 @@ export class CompilationEnv { return file ? projectFile(this.system, this.buildDir, file) : undefined; } - private resolveSourcePaths(addonName: string, addonFiles: Record, addonTargetPath: string): Record { + private resolveAddonSourcePaths(addonName: string, addonFiles: Record, addonTargetPath: string): Record { + if (!this.addons) { + return {}; + } return Object.entries(addonFiles).reduce((acc: Record, [filePath, content]) => { if (isAbsolute(filePath)) { acc[filePath] = content; } else { if (filePath.includes(addonName)) { - acc[join(this.getAddonsDir(), filePath)] = content; + acc[join(this.addons!.getAddonsDir(), filePath)] = content; } else { acc[join(addonTargetPath, filePath)] = content; } @@ -321,10 +347,6 @@ export class CompilationEnv { this.compilerOptions.tsconfig.fileNames.push(filePath); } } - - private getAddonRegistry(): AddonRegistry { - return this.compilerOptions.addons; - } } export type CompilationResult = { @@ -375,4 +397,5 @@ const projectFiles = (result: ProjectFile[]): ProjectFiles => { return Object.assign(result, { getPaths: () => result.map(it => it.getPath()), getContents: () => result.map(it => it.getContent()!) }); }; -export const compilationEnv = (rootDir: string, options?: CompilationOptions): CompilationEnv => new CompilationEnv(rootDir, options); +export const compilationEnv = (rootDir: string, options?: CompilationOptions, addonConfig?: AddonRegistryOptions): CompilationEnv => + new CompilationEnv(rootDir, options, addonConfig); diff --git a/packages/testing/src/compile-options.spec.ts b/packages/testing/src/compile-options.spec.ts index 41581031..e77df5b9 100644 --- a/packages/testing/src/compile-options.spec.ts +++ b/packages/testing/src/compile-options.spec.ts @@ -13,7 +13,6 @@ describe("compileOptions", () => { const actual = compileOptions(createBrowserSystem()); expect(actual).toEqual({ - addons: expect.any(Object), buildDir: "/src", reporter: expect.any(Object), debug: false, diff --git a/packages/testing/src/compile-options.ts b/packages/testing/src/compile-options.ts index 458ee3a0..5ef72b99 100644 --- a/packages/testing/src/compile-options.ts +++ b/packages/testing/src/compile-options.ts @@ -4,14 +4,13 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { AddonRegistry, type CompilerOptions } from "@quatico/websmith-core"; +import { type CompilerOptions } from "@quatico/websmith-core"; import ts from "typescript"; import { ReporterMock } from "./ReporterMock"; import { resolvePath } from "./compilation/resolve-path"; const DEFAULT_BUILD_DIR = "./src"; const DEFAULT_OUT_DIR = "./dist"; -const DEFAULT_ADDONS_DIR = "../addons"; export const compileOptions = ( system: ts.System, @@ -20,9 +19,7 @@ export const compileOptions = ( ): CompilerOptions => { const reporter = new ReporterMock(system); const buildDir: string = resolvePath(system, overrides?.buildDir ?? DEFAULT_BUILD_DIR); - const addonsDirPath = resolvePath(system, buildDir, DEFAULT_ADDONS_DIR); return { - addons: new AddonRegistry({ addonsDir: addonsDirPath, reporter, system }), buildDir, reporter, debug: false, diff --git a/packages/testing/src/compile-system.ts b/packages/testing/src/compile-system.ts index 74d4455f..369ba0ff 100644 --- a/packages/testing/src/compile-system.ts +++ b/packages/testing/src/compile-system.ts @@ -4,21 +4,27 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { createBrowserSystem, getVersionedFile } from "@quatico/websmith-core"; +import { Reporter } from "@quatico/websmith-api"; +import { AddonRegistry, AddonRegistryOptions, NoReporter, createBrowserSystem, getVersionedFile } from "@quatico/websmith-core"; import ts from "typescript"; export type CompileSystem = { fileSystem: ts.System; getSourceFile(fileName: string): { entry?: ts.SourceFile; fileSystem: ts.System }; + addons: AddonRegistry; }; export type CompileSystemOptions = { useCaseSensitiveFileNames?: boolean; withDefaultFiles?: boolean; + files?: Record; + addonConfig?: Partial; + reporter?: Reporter; }; -export const compileSystem = (files?: Record, options?: CompileSystemOptions): CompileSystem => { - const { useCaseSensitiveFileNames = false, withDefaultFiles = true } = options ?? {}; +export const compileSystem = (options?: CompileSystemOptions): CompileSystem => { + const { files, addonConfig, reporter, useCaseSensitiveFileNames = false, withDefaultFiles = true } = options ?? {}; + const fileSystem = createBrowserSystem({ ...files }, useCaseSensitiveFileNames); if (withDefaultFiles) { if (!fileSystem.fileExists("./tsconfig.json")) { @@ -31,8 +37,20 @@ export const compileSystem = (files?: Record, options?: CompileS fileSystem.createDirectory("./addons"); } } + + const { addons = "", addonsDir = "./addons", targets } = addonConfig ?? JSON.parse(fileSystem.readFile("./websmith.config.json") ?? "{}"); + + const registry = new AddonRegistry({ + addons, + addonsDir, + targets, + reporter: reporter ?? new NoReporter(), + system: fileSystem, + }); + return { fileSystem, + addons: registry, getSourceFile: (fileName: string) => ({ entry: getVersionedFile(fileName, fileSystem), fileSystem, diff --git a/packages/webpack/src/TsCompiler.ts b/packages/webpack/src/TsCompiler.ts index 841feaa1..f93b129d 100644 --- a/packages/webpack/src/TsCompiler.ts +++ b/packages/webpack/src/TsCompiler.ts @@ -5,11 +5,11 @@ * --------------------------------------------------------------------------------------------- */ -import { CompileFragment, Compiler, CompilerOptions } from "@quatico/websmith-core"; +import { AddonRegistry, CompileFragment, Compiler, CompilerOptions } from "@quatico/websmith-core"; import ts from "typescript"; import { WebpackError } from "webpack"; -import { PluginOptions } from "./loader-options"; import { Upath as uPath } from "./Upath"; +import { PluginOptions } from "./loader-options"; export class TsCompiler extends Compiler { public fragment?: CompileFragment; @@ -19,7 +19,14 @@ export class TsCompiler extends Compiler { constructor(options: CompilerOptions, dependencyCallback: (filePath: string) => void, pluginOptions?: PluginOptions) { pluginOptions = pluginOptions ? { webpackTarget: "*", ...pluginOptions } : { config: "", webpackTarget: "*" }; - super(options, ts.sys, dependencyCallback); + super( + options, + ts.sys, + pluginOptions.addonsDir + ? new AddonRegistry({ addons: pluginOptions.addons, addonsDir: pluginOptions.addonsDir, reporter: options.reporter, system: ts.sys }) + : undefined, + dependencyCallback + ); this.pluginConfig = pluginOptions; super.createTargetContextsIfNecessary(); this.targets = options.targets; diff --git a/packages/webpack/src/options.spec.ts b/packages/webpack/src/options.spec.ts index 77cdffec..17360906 100644 --- a/packages/webpack/src/options.spec.ts +++ b/packages/webpack/src/options.spec.ts @@ -4,7 +4,7 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { CompilerAddon, NoReporter } from "@quatico/websmith-core"; +import { NoReporter } from "@quatico/websmith-core"; import { compileSystem } from "@quatico/websmith-testing"; import { createOptions } from "./options"; @@ -23,7 +23,7 @@ describe("createOptions", () => { }); it("should return project config w/ custom but empty tsconfig.json", () => { - const { fileSystem: target } = compileSystem({ "./expected/tsconfig.json": "{}" }); + const { fileSystem: target } = compileSystem({ files: { "./expected/tsconfig.json": "{}" } }); const actual = createOptions({ project: "./expected/tsconfig.json" }, new NoReporter(), target).project; @@ -34,9 +34,12 @@ describe("createOptions", () => { }); it("should return expected path w/ custom addons directory", () => { - const { fileSystem: target } = compileSystem({ - "./tsconfig.json": "{}", - "./expected/addon-foo/addon.js": "export const activate = () => {};", + const { addons } = compileSystem({ + files: { + "./tsconfig.json": "{}", + "./expected/addon-foo/addon.js": "export const activate = () => {};", + }, + addonConfig: { addons: "addon-foo", addonsDir: "./expected" }, }); jest.mock( "/expected/addon-foo/addon", @@ -46,13 +49,13 @@ describe("createOptions", () => { { virtual: true } ); - const actual: CompilerAddon[] = createOptions({ addonsDir: "./expected" }, new NoReporter(), target).addons.refresh().getAvailableAddons(); + const actual = addons.refresh().getAvailableAddons(); expect(actual.map(it => it.getName())).toEqual(["addon-foo"]); }); it("should return debug path w/ debug true", () => { - const { fileSystem: target } = compileSystem({ "./tsconfig.json": "{}" }); + const { fileSystem: target } = compileSystem({ files: { "./tsconfig.json": "{}" } }); const actual = createOptions({ debug: true }, new NoReporter(), target); @@ -61,10 +64,12 @@ describe("createOptions", () => { it("should return config w/ valid compiler config json", () => { const { fileSystem: target } = compileSystem({ - "./tsconfig.json": "{}", - "websmith.config.json": ` + files: { + "./tsconfig.json": "{}", + "websmith.config.json": ` { "targets": { "whatever": { "addons": [ "one", "two", "three" ], "writeFile": true } } } `, + }, }); const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).config; @@ -75,10 +80,12 @@ describe("createOptions", () => { }); it("should return config w/ valid addonsDir, addons in compiler config json", () => { - const { fileSystem: target } = compileSystem({ - "./tsconfig.json": "{}", - "/expected/one/addon.js": "export const activate = () => {};", - "websmith.config.json": '{ "addons":["one", "two"], "addonsDir":"./expected" }', + const { addons } = compileSystem({ + files: { + "./tsconfig.json": "{}", + "/expected/one/addon.js": "export const activate = () => {};", + "websmith.config.json": '{ "addons":["one", "two"], "addonsDir":"./expected" }', + }, }); jest.mock( "/expected/one/addon", @@ -88,7 +95,7 @@ describe("createOptions", () => { { virtual: true } ); - const actual = createOptions({ config: "./websmith.config.json" }, new NoReporter(), target).addons.refresh(); + const actual = addons.refresh(); expect(actual).toMatchObject({ availableAddons: new Map( @@ -100,13 +107,8 @@ describe("createOptions", () => { }) ), options: { - addons: "one,two", - addonsDir: "/expected", - config: { - addons: ["one", "two"], - addonsDir: "/expected", - configFilePath: "/websmith.config.json", - }, + addons: ["one", "two"], + addonsDir: "./expected", }, }); }); diff --git a/packages/webpack/src/options.ts b/packages/webpack/src/options.ts index d38bd6c5..04d95c00 100644 --- a/packages/webpack/src/options.ts +++ b/packages/webpack/src/options.ts @@ -6,12 +6,11 @@ */ import { Reporter } from "@quatico/websmith-api"; import { - AddonRegistry, CompilerOptions, NoReporter, resolveCompilationConfig, - resolveProjectConfig as resolveTsConfig, resolveTargets, + resolveProjectConfig as resolveTsConfig, updateCompilerOptions, } from "@quatico/websmith-core"; import { dirname, join } from "path"; @@ -55,13 +54,6 @@ export const createOptions = (args: Partial, reporter: Reporter = }; return { - addons: new AddonRegistry({ - addons: args.addons ?? compilationConfig?.addons?.join(","), - addonsDir: args.addonsDir && args.addonsDir !== DEFAULTS.addonsDir ? args.addonsDir : compilationConfig?.addonsDir ?? DEFAULTS.addonsDir, - config: compilationConfig, - reporter, - system, - }), buildDir: args.buildDir ?? system.getCurrentDirectory(), config: compilationConfig, debug: args.debug ?? DEFAULTS.debug, From 568bf7000723c1c1569a6ac2a7fd126d546a5717 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 5 May 2024 23:15:10 +0200 Subject: [PATCH 38/52] r Don't reselect transitive exports --- packages/core/src/compiler/addons/index.ts | 8 ++--- packages/core/src/compiler/index.ts | 23 ++++---------- packages/core/src/index.ts | 37 ++-------------------- 3 files changed, 12 insertions(+), 56 deletions(-) diff --git a/packages/core/src/compiler/addons/index.ts b/packages/core/src/compiler/addons/index.ts index 2d719e9e..031a2b0f 100644 --- a/packages/core/src/compiler/addons/index.ts +++ b/packages/core/src/compiler/addons/index.ts @@ -5,8 +5,8 @@ * --------------------------------------------------------------------------------------------- */ import { createResolver } from "./addon-resolver"; -import { AddonRegistry } from "./AddonRegistry"; -import type { CompilerAddon } from "./CompilerAddon"; +import { AddonRegistry, type AddonRegistryOptions } from "./AddonRegistry"; +import { compilerAddons, type CompilerAddon, type CompilerAddons } from "./CompilerAddon"; -export { AddonRegistry, createResolver }; -export type { CompilerAddon }; +export { AddonRegistry, compilerAddons, createResolver }; +export type { AddonRegistryOptions, CompilerAddon, CompilerAddons }; diff --git a/packages/core/src/compiler/index.ts b/packages/core/src/compiler/index.ts index 72066898..23beae97 100644 --- a/packages/core/src/compiler/index.ts +++ b/packages/core/src/compiler/index.ts @@ -4,26 +4,15 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { AddonRegistry, CompilerAddon } from "./addons"; -import type { CompilationContext } from "./compilation"; import type { CompileFragment } from "./Compiler"; import { Compiler } from "./Compiler"; import type { CompilerOptions } from "./CompilerOptions"; -import { CompilationConfig, resolveCompilationConfig, resolveProjectConfig, resolveTargets, updateCompilerOptions } from "./config"; import { DefaultReporter } from "./DefaultReporter"; -import { tsDefaults, tsLibDefaults } from "./defaults"; import { NoReporter } from "./NoReporter"; +import { tsDefaults, tsLibDefaults } from "./defaults"; -export { - AddonRegistry, - Compiler, - DefaultReporter, - NoReporter, - resolveCompilationConfig, - resolveProjectConfig, - resolveTargets, - tsDefaults, - tsLibDefaults, - updateCompilerOptions, -}; -export type { CompilerAddon, CompilationConfig, CompileFragment, CompilerOptions, CompilationContext }; +export * from "./addons"; +export * from "./compilation"; +export * from "./config"; +export { Compiler, DefaultReporter, NoReporter, tsDefaults, tsLibDefaults }; +export type { CompileFragment, CompilerOptions }; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 5211ddc6..cea76347 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -4,38 +4,5 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import type { CompilationContext, CompileFragment, CompilerAddon, CompilerOptions } from "./compiler"; -import { - AddonRegistry, - CompilationConfig, - Compiler, - DefaultReporter, - NoReporter, - resolveCompilationConfig, - resolveProjectConfig, - resolveTargets, - tsDefaults, - tsLibDefaults, - updateCompilerOptions, -} from "./compiler"; -import { createBrowserSystem, createCompileHost, createSystem, createVersionedFiles, getVersionedFile, readFiles } from "./environment"; - -export { - AddonRegistry, - Compiler, - createBrowserSystem, - createCompileHost, - createSystem, - createVersionedFiles, - DefaultReporter, - getVersionedFile, - NoReporter, - readFiles, - resolveCompilationConfig, - resolveProjectConfig, - resolveTargets, - tsDefaults, - tsLibDefaults, - updateCompilerOptions, -}; -export type { CompilerAddon, CompileFragment, CompilationConfig, CompilerOptions, CompilationContext }; +export * from "./compiler"; +export * from "./environment"; From ba9b4ddd29daa679fd72889ae5c35f6d3db18954 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 5 May 2024 23:15:55 +0200 Subject: [PATCH 39/52] t Hides unrelated warning in test --- packages/testing/jest.config.js | 1 + packages/testing/src/compilation/environment.spec.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/testing/jest.config.js b/packages/testing/jest.config.js index 3c5c4946..d5cb65fc 100644 --- a/packages/testing/jest.config.js +++ b/packages/testing/jest.config.js @@ -30,4 +30,5 @@ module.exports = { ], }, resetMocks: true, + restoreMocks: true, }; diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index 73bc4c58..2b7c7126 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -92,6 +92,7 @@ describe("compilationEnv#addons", () => { }); it("should yield no addons with invalid addon source", () => { + console.warn = jest.fn(); const testObj = compilationEnv("/target").addAddon("invalid-addon", { "addon.ts": `export const NO_ACTIVATE_FUNCTION = true;` }); const actual = testObj.getActiveAddons(); From 474b7f27b2bd5a3770685e2ea07c229380345644 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 5 May 2024 23:16:16 +0200 Subject: [PATCH 40/52] t Removes debug log statement from test --- packages/core/src/compiler/Compiler.spec.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/core/src/compiler/Compiler.spec.ts b/packages/core/src/compiler/Compiler.spec.ts index 8463a6b8..7c63e05a 100644 --- a/packages/core/src/compiler/Compiler.spec.ts +++ b/packages/core/src/compiler/Compiler.spec.ts @@ -773,10 +773,7 @@ describe("watch", () => { }); it("yields multiple code transpilations w/ a shared asset dependency", () => { - const target = jest.fn().mockImplementation((fileName: string, target: string, writeFile: boolean, skipCache = false) => { - console.debug("XXX target", fileName, target, writeFile, skipCache); - return; - }); + const target = jest.fn(); const { fileSystem } = compileSystem({ "src/shared.scss": ` { From 1c978555135b240b7c57b8d3de67dae0182581cf Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 5 May 2024 23:28:23 +0200 Subject: [PATCH 41/52] r Renames AddonRegistryOptions to AddonConfig --- packages/compiler/src/command.spec.ts | 2 +- packages/compiler/src/command.ts | 2 +- packages/compiler/src/options.spec.ts | 2 +- .../core/src/compiler/addons/AddonRegistry.ts | 20 +++++++++---------- packages/core/src/compiler/addons/index.ts | 4 ++-- .../testing/src/compilation/environment.ts | 10 +++++----- packages/testing/src/compile-system.ts | 4 ++-- packages/webpack/src/options.spec.ts | 2 +- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/compiler/src/command.spec.ts b/packages/compiler/src/command.spec.ts index 2d1006e6..766c2478 100644 --- a/packages/compiler/src/command.spec.ts +++ b/packages/compiler/src/command.spec.ts @@ -280,7 +280,7 @@ describe("addCompileCommand#addons", () => { addCompileCommand(new Command(), target).parse([], { from: "user" }); expect(addons).toMatchObject({ - options: { + config: { addons: "one,two", addonsDir: "/expected", }, diff --git a/packages/compiler/src/command.ts b/packages/compiler/src/command.ts index ab8e7c32..67193be2 100644 --- a/packages/compiler/src/command.ts +++ b/packages/compiler/src/command.ts @@ -81,7 +81,7 @@ export const addCompileCommand = (parent = program, compiler?: Compiler): Comman compiler .setOptions(options) .getAddonRegistry() - ?.setOptions({ + ?.setConfig({ addons: command.opts().addons ?? compilationConfig?.addons?.join(","), addonsDir: command.opts().addonsDir && command.opts().addonsDir !== "./addons" diff --git a/packages/compiler/src/options.spec.ts b/packages/compiler/src/options.spec.ts index 1b920d48..eb06546f 100644 --- a/packages/compiler/src/options.spec.ts +++ b/packages/compiler/src/options.spec.ts @@ -115,7 +115,7 @@ describe("createOptions", () => { }, }) ), - options: { + config: { addonsDir: "./expected", addons: ["one", "two"], }, diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index e5b24223..76a3235d 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -9,7 +9,7 @@ import path, { basename, extname } from "path"; import ts from "typescript"; import { compilerAddons, type CompilerAddon, type CompilerAddons } from "./CompilerAddon"; -export type AddonRegistryOptions = { +export type AddonConfig = { addons?: string; addonsDir: string; targets?: Record; @@ -19,20 +19,20 @@ export type AddonRegistryOptions = { export class AddonRegistry { private availableAddons: Map; - private options: AddonRegistryOptions; + private config: AddonConfig; - constructor(options: AddonRegistryOptions) { + constructor(config: AddonConfig) { this.availableAddons = new Map(); - this.options = { ...options }; + this.config = { ...config }; } - setOptions(options: Partial): this { - this.options = { ...this.options, ...options }; + setConfig(config: Partial): this { + this.config = { ...this.config, ...config }; return this.refresh(); } public getAddonsDir(): string { - return this.options.addonsDir; + return this.config.addonsDir; } public getAvailableAddons(target?: string): CompilerAddons { @@ -51,7 +51,7 @@ export class AddonRegistry { } private getExpectedAddons(target?: string): string[] { - const { targets = {}, addons } = this.options; + const { targets = {}, addons } = this.config; const requestedAddons = addons ?.split(",") @@ -68,7 +68,7 @@ export class AddonRegistry { } private reportMissingAddons(target?: string): void { - const { reporter } = this.options; + const { reporter } = this.config; const missing = this.getMissingAddons(target).join(", "); if (missing.length > 0) { @@ -79,7 +79,7 @@ export class AddonRegistry { } private findAddons(): Map { - const { addonsDir, reporter, system } = this.options; + const { addonsDir, reporter, system } = this.config; const map = new Map(); if (addonsDir && !system.directoryExists(addonsDir)) { diff --git a/packages/core/src/compiler/addons/index.ts b/packages/core/src/compiler/addons/index.ts index 031a2b0f..87ba429a 100644 --- a/packages/core/src/compiler/addons/index.ts +++ b/packages/core/src/compiler/addons/index.ts @@ -5,8 +5,8 @@ * --------------------------------------------------------------------------------------------- */ import { createResolver } from "./addon-resolver"; -import { AddonRegistry, type AddonRegistryOptions } from "./AddonRegistry"; +import { AddonRegistry, type AddonConfig } from "./AddonRegistry"; import { compilerAddons, type CompilerAddon, type CompilerAddons } from "./CompilerAddon"; export { AddonRegistry, compilerAddons, createResolver }; -export type { AddonRegistryOptions, CompilerAddon, CompilerAddons }; +export type { AddonConfig, CompilerAddon, CompilerAddons }; diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 55eae007..1293526e 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -6,7 +6,7 @@ */ import { AddonRegistry, - AddonRegistryOptions, + AddonConfig, Compiler, CompilerAddons, DefaultReporter, @@ -37,7 +37,7 @@ export class CompilationEnv { private virtual: boolean; private addons?: AddonRegistry; - constructor(rootDir?: string, options?: CompilationOptions, addonsConfig?: AddonRegistryOptions) { + constructor(rootDir?: string, options?: CompilationOptions, addonConfig?: AddonConfig) { const { virtual = true, compilerOptions = {}, useCaseSensitiveFileNames } = options ?? {}; this.virtual = virtual; this.system = this.virtual ? createBrowserSystem(undefined, useCaseSensitiveFileNames) : ts.sys; @@ -72,14 +72,14 @@ export class CompilationEnv { ...compilerOptions, }); - if (!addonsConfig) { - addonsConfig = { + if (!addonConfig) { + addonConfig = { addonsDir: join(this.rootDir, "./addons"), reporter: new DefaultReporter(this.system), system: this.system, }; } - this.addons = new AddonRegistry(addonsConfig); + this.addons = new AddonRegistry(addonConfig); if (!this.system.directoryExists(this.addons.getAddonsDir())) { this.system.createDirectory(this.addons.getAddonsDir()); } diff --git a/packages/testing/src/compile-system.ts b/packages/testing/src/compile-system.ts index 369ba0ff..afec2425 100644 --- a/packages/testing/src/compile-system.ts +++ b/packages/testing/src/compile-system.ts @@ -5,7 +5,7 @@ * --------------------------------------------------------------------------------------------- */ import { Reporter } from "@quatico/websmith-api"; -import { AddonRegistry, AddonRegistryOptions, NoReporter, createBrowserSystem, getVersionedFile } from "@quatico/websmith-core"; +import { AddonRegistry, AddonConfig, NoReporter, createBrowserSystem, getVersionedFile } from "@quatico/websmith-core"; import ts from "typescript"; export type CompileSystem = { @@ -18,7 +18,7 @@ export type CompileSystemOptions = { useCaseSensitiveFileNames?: boolean; withDefaultFiles?: boolean; files?: Record; - addonConfig?: Partial; + addonConfig?: Partial; reporter?: Reporter; }; diff --git a/packages/webpack/src/options.spec.ts b/packages/webpack/src/options.spec.ts index 17360906..49c1b40c 100644 --- a/packages/webpack/src/options.spec.ts +++ b/packages/webpack/src/options.spec.ts @@ -106,7 +106,7 @@ describe("createOptions", () => { }, }) ), - options: { + config: { addons: ["one", "two"], addonsDir: "./expected", }, From e102343e1e1e72b78f96e0956a9c996153f4fac3 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Sun, 5 May 2024 23:51:46 +0200 Subject: [PATCH 42/52] R Use string[] for addons in compiler code --- packages/compiler/src/command.spec.ts | 4 +-- packages/compiler/src/command.ts | 35 ++++++++++--------- .../src/compiler/addons/AddonRegistry.spec.ts | 12 +++---- .../core/src/compiler/addons/AddonRegistry.ts | 10 ++---- .../testing/src/compilation/environment.ts | 2 +- packages/testing/src/compile-system.ts | 2 +- packages/webpack/src/TsCompiler.ts | 11 +++++- packages/webpack/src/options.spec.ts | 2 +- 8 files changed, 42 insertions(+), 36 deletions(-) diff --git a/packages/compiler/src/command.spec.ts b/packages/compiler/src/command.spec.ts index 766c2478..6bdbb047 100644 --- a/packages/compiler/src/command.spec.ts +++ b/packages/compiler/src/command.spec.ts @@ -281,7 +281,7 @@ describe("addCompileCommand#addons", () => { expect(addons).toMatchObject({ config: { - addons: "one,two", + addons: ["one", "two"], addonsDir: "/expected", }, availableAddons: new Map( @@ -377,7 +377,7 @@ describe("addCompileCommand#targets", () => { expect(target.reportDiagnostic).toHaveBeenCalledWith( new WarnMessage( - 'Custom target configuration "unknown,known" found, but no target provided.\n\tSome custom addons may not be applied during compilation.' + 'Custom target configuration "unknown, known" found, but no target provided.\n\tSome custom addons may not be applied during compilation.' ) ); }); diff --git a/packages/compiler/src/command.ts b/packages/compiler/src/command.ts index 67193be2..4df5b36a 100644 --- a/packages/compiler/src/command.ts +++ b/packages/compiler/src/command.ts @@ -5,11 +5,11 @@ * --------------------------------------------------------------------------------------------- */ import { WarnMessage } from "@quatico/websmith-api"; -import { AddonRegistry, CompilationConfig, Compiler, DefaultReporter, resolveCompilationConfig } from "@quatico/websmith-core"; +import { AddonRegistry, CompilationConfig, Compiler, CompilerOptions, DefaultReporter, resolveCompilationConfig } from "@quatico/websmith-core"; import { Command, program } from "commander"; import parseArgs from "minimist"; -import { compileSystem } from "./compiler-system"; import { CompilerArguments } from "./CompilerArguments"; +import { compileSystem } from "./compiler-system"; import { createOptions } from "./options"; export const addCompileCommand = (parent = program, compiler?: Compiler): Command => { @@ -56,7 +56,7 @@ export const addCompileCommand = (parent = program, compiler?: Compiler): Comman if (hasInvalidTargets(options.targets, options.config)) { reporter.reportDiagnostic( new WarnMessage( - `Custom target configuration "${options.targets.join(",")}" found, but no target provided.\n` + + `Custom target configuration "${options.targets.join(", ")}" found, but no target provided.\n` + `\tSome custom addons may not be applied during compilation.` ) ); @@ -66,12 +66,7 @@ export const addCompileCommand = (parent = program, compiler?: Compiler): Comman let addons; if (command.opts().addonsDir || command.opts().addons) { addons = new AddonRegistry({ - addons: command.opts().addons ?? compilationConfig?.addons?.join(","), - addonsDir: - command.opts().addonsDir && command.opts().addonsDir !== "./addons" - ? command.opts().addonsDir - : compilationConfig?.addonsDir ?? "./addons", - targets: options.config?.targets, + ...addonConfig(command, compilationConfig, options), reporter, system, }); @@ -81,14 +76,7 @@ export const addCompileCommand = (parent = program, compiler?: Compiler): Comman compiler .setOptions(options) .getAddonRegistry() - ?.setConfig({ - addons: command.opts().addons ?? compilationConfig?.addons?.join(","), - addonsDir: - command.opts().addonsDir && command.opts().addonsDir !== "./addons" - ? command.opts().addonsDir - : compilationConfig?.addonsDir ?? "./addons", - targets: options.config?.targets, - }); + ?.setConfig(addonConfig(command, compilationConfig, options)); } if (args.watch) { @@ -100,6 +88,19 @@ export const addCompileCommand = (parent = program, compiler?: Compiler): Comman return parent; }; +const addonConfig = (command: Command, compilationConfig?: CompilationConfig, options?: CompilerOptions) => ({ + addons: + (command.opts().addons ?? compilationConfig?.addons?.join(",") ?? "") + ?.split(",") + .map((it: string) => it.trim()) + .filter((it: string) => it.length > 0) ?? [], + + addonsDir: + command.opts().addonsDir && command.opts().addonsDir !== "./addons" ? command.opts().addonsDir : compilationConfig?.addonsDir ?? "./addons", + + targets: options?.config?.targets, +}); + export const hasInvalidTargets = (targets?: string[], config?: CompilationConfig) => { if (targets === undefined || targets.length === 0 || (targets[0] === "*" && targets.length === 1)) { return false; diff --git a/packages/core/src/compiler/addons/AddonRegistry.spec.ts b/packages/core/src/compiler/addons/AddonRegistry.spec.ts index 5b7487b3..fcb1fe59 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.spec.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.spec.ts @@ -83,7 +83,7 @@ describe("getAvailableAddons", () => { reporter.reportDiagnostic = jest.fn(); new AddonRegistry({ - addons: "does-not-exist", + addons: ["does-not-exist"], addonsDir: "./addons", reporter, system, @@ -187,7 +187,7 @@ describe("getExpectedAddons", () => { }); it("returns addons w/ addons", () => { - const testObj = new AddonRegistry({ addons: "one, two, three", addonsDir: "./empty", reporter, system }); + const testObj = new AddonRegistry({ addons: ["one", "two", "three"], addonsDir: "./empty", reporter, system }); // @ts-expect-error private property access expect(testObj.getExpectedAddons()).toEqual(["one", "two", "three"]); @@ -239,7 +239,7 @@ describe("getMissingAddons", () => { }); it("returns missing addons w/ missing addons", () => { - const testObj = new AddonRegistry({ addons: "missing", addonsDir: "./target", reporter, system }); + const testObj = new AddonRegistry({ addons: ["missing"], addonsDir: "./target", reporter, system }); // @ts-expect-error private property access expect(testObj.getMissingAddons()).toEqual(["missing"]); @@ -248,7 +248,7 @@ describe("getMissingAddons", () => { it("returns missing addons w/ missing and available addons", () => { createAddon("target/expected/addon"); - const testObj = new AddonRegistry({ addons: "missing, expected", addonsDir: "./target", reporter, system }).refresh(); + const testObj = new AddonRegistry({ addons: ["missing", "expected"], addonsDir: "./target", reporter, system }).refresh(); // @ts-expect-error private property access expect(testObj.getMissingAddons()).toEqual(["missing"]); @@ -271,7 +271,7 @@ describe("reportMissingAddons", () => { system.createDirectory("./target"); reporter.reportDiagnostic = jest.fn(); - new AddonRegistry({ addonsDir: "./target", addons: "missing", reporter, system }).getAvailableAddons(); + new AddonRegistry({ addonsDir: "./target", addons: ["missing"], reporter, system }).getAvailableAddons(); expect(reporter.reportDiagnostic).toHaveBeenCalledWith(new WarnMessage('Missing addons: "missing".')); }); @@ -281,7 +281,7 @@ describe("reportMissingAddons", () => { createAddon("target/expected/addon"); reporter.reportDiagnostic = jest.fn(); - new AddonRegistry({ addonsDir: "./target", addons: "expected", reporter, system }).refresh().getAvailableAddons(); + new AddonRegistry({ addonsDir: "./target", addons: ["expected"], reporter, system }).refresh().getAvailableAddons(); expect(reporter.reportDiagnostic).not.toHaveBeenCalled(); }); diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index 76a3235d..83fecaf3 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -10,7 +10,7 @@ import ts from "typescript"; import { compilerAddons, type CompilerAddon, type CompilerAddons } from "./CompilerAddon"; export type AddonConfig = { - addons?: string; + addons?: string[]; addonsDir: string; targets?: Record; reporter: Reporter; @@ -51,12 +51,8 @@ export class AddonRegistry { } private getExpectedAddons(target?: string): string[] { - const { targets = {}, addons } = this.config; - const requestedAddons = - addons - ?.split(",") - .map(it => it.trim()) - .filter(it => it.length > 0) ?? []; + const { targets = {}, addons = [] } = this.config; + const requestedAddons = addons.filter(it => it.length > 0); const targetAddons = target ? targets[target]?.addons ?? [] : []; diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 1293526e..b3132e42 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -397,5 +397,5 @@ const projectFiles = (result: ProjectFile[]): ProjectFiles => { return Object.assign(result, { getPaths: () => result.map(it => it.getPath()), getContents: () => result.map(it => it.getContent()!) }); }; -export const compilationEnv = (rootDir: string, options?: CompilationOptions, addonConfig?: AddonRegistryOptions): CompilationEnv => +export const compilationEnv = (rootDir: string, options?: CompilationOptions, addonConfig?: AddonConfig): CompilationEnv => new CompilationEnv(rootDir, options, addonConfig); diff --git a/packages/testing/src/compile-system.ts b/packages/testing/src/compile-system.ts index afec2425..33013d97 100644 --- a/packages/testing/src/compile-system.ts +++ b/packages/testing/src/compile-system.ts @@ -38,7 +38,7 @@ export const compileSystem = (options?: CompileSystemOptions): CompileSystem => } } - const { addons = "", addonsDir = "./addons", targets } = addonConfig ?? JSON.parse(fileSystem.readFile("./websmith.config.json") ?? "{}"); + const { addons = [], addonsDir = "./addons", targets } = addonConfig ?? JSON.parse(fileSystem.readFile("./websmith.config.json") ?? "{}"); const registry = new AddonRegistry({ addons, diff --git a/packages/webpack/src/TsCompiler.ts b/packages/webpack/src/TsCompiler.ts index f93b129d..f3096789 100644 --- a/packages/webpack/src/TsCompiler.ts +++ b/packages/webpack/src/TsCompiler.ts @@ -23,7 +23,16 @@ export class TsCompiler extends Compiler { options, ts.sys, pluginOptions.addonsDir - ? new AddonRegistry({ addons: pluginOptions.addons, addonsDir: pluginOptions.addonsDir, reporter: options.reporter, system: ts.sys }) + ? new AddonRegistry({ + addons: + (pluginOptions.addons ?? "") + ?.split(",") + .map(it => it.trim()) + .filter(it => it.length > 0) ?? [], + addonsDir: pluginOptions.addonsDir, + reporter: options.reporter, + system: ts.sys, + }) : undefined, dependencyCallback ); diff --git a/packages/webpack/src/options.spec.ts b/packages/webpack/src/options.spec.ts index 49c1b40c..bd2c86fa 100644 --- a/packages/webpack/src/options.spec.ts +++ b/packages/webpack/src/options.spec.ts @@ -39,7 +39,7 @@ describe("createOptions", () => { "./tsconfig.json": "{}", "./expected/addon-foo/addon.js": "export const activate = () => {};", }, - addonConfig: { addons: "addon-foo", addonsDir: "./expected" }, + addonConfig: { addons: ["addon-foo"], addonsDir: "./expected" }, }); jest.mock( "/expected/addon-foo/addon", From 8b5fdc3dee2ccb9b903a05e370752b79f29ff63e Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Mon, 6 May 2024 13:00:01 +0200 Subject: [PATCH 43/52] r Tidy packages exports --- packages/api/src/index.ts | 25 +++++++-------- packages/compiler/src/index.ts | 9 ++---- packages/core/src/compiler/addons/index.ts | 9 ++---- packages/core/src/compiler/cache/index.ts | 7 ++-- .../core/src/compiler/compilation/index.ts | 8 ++--- packages/core/src/compiler/config/index.ts | 11 +++---- packages/core/src/compiler/index.ts | 15 ++++----- packages/core/src/editing/index.ts | 4 +-- packages/core/src/environment/index.ts | 27 +++------------- packages/testing/src/index.ts | 10 +++--- packages/webpack/src/index.ts | 32 ++----------------- packages/webpack/src/loader-options.ts | 4 +-- packages/webpack/src/loader.ts | 23 +++++++++++++ 13 files changed, 71 insertions(+), 113 deletions(-) create mode 100644 packages/webpack/src/loader.ts diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index f4b1d550..b661cbd6 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -4,17 +4,14 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import type { AddonActivator } from "./AddonActivator"; -import type { AddonContext } from "./AddonContext"; -import { ErrorMessage } from "./ErrorMessage"; -import type { Generator } from "./Generator"; -import { InfoMessage } from "./InfoMessage"; -import { aggregateMessages, messageToString } from "./messages"; -import type { Processor } from "./Processor"; -import type { Reporter } from "./Reporter"; -import type { ResultProcessor } from "./ResultProcessor"; -import type { TargetConfig } from "./TargetConfig"; -import { WarnMessage } from "./WarnMessage"; - -export type { AddonActivator, AddonContext, Generator, TargetConfig, ResultProcessor, Processor, Reporter }; -export { ErrorMessage, WarnMessage, InfoMessage, aggregateMessages, messageToString }; +export type { AddonActivator } from "./AddonActivator"; +export type { AddonContext } from "./AddonContext"; +export { ErrorMessage } from "./ErrorMessage"; +export type { Generator } from "./Generator"; +export { InfoMessage } from "./InfoMessage"; +export { aggregateMessages, messageToString } from "./messages"; +export type { Processor } from "./Processor"; +export type { Reporter } from "./Reporter"; +export type { ResultProcessor } from "./ResultProcessor"; +export type { TargetConfig } from "./TargetConfig"; +export { WarnMessage } from "./WarnMessage"; diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index c4a72e82..925bafcc 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -4,11 +4,8 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { addCompileCommand } from "./command"; -import type { CompilerArguments } from "./CompilerArguments"; -import { createOptions } from "./options"; - +export { addCompileCommand } from "./command"; +export type { CompilerArguments } from "./CompilerArguments"; +export { createOptions } from "./options"; export { Compiler, createBrowserSystem, DefaultReporter, getVersionedFile, NoReporter } from "@quatico/websmith-core"; export type { CompilerOptions } from "@quatico/websmith-core"; -export { addCompileCommand, createOptions }; -export type { CompilerArguments }; diff --git a/packages/core/src/compiler/addons/index.ts b/packages/core/src/compiler/addons/index.ts index 87ba429a..673df913 100644 --- a/packages/core/src/compiler/addons/index.ts +++ b/packages/core/src/compiler/addons/index.ts @@ -4,9 +4,6 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { createResolver } from "./addon-resolver"; -import { AddonRegistry, type AddonConfig } from "./AddonRegistry"; -import { compilerAddons, type CompilerAddon, type CompilerAddons } from "./CompilerAddon"; - -export { AddonRegistry, compilerAddons, createResolver }; -export type { AddonConfig, CompilerAddon, CompilerAddons }; +export { createResolver } from "./addon-resolver"; +export { AddonRegistry } from "./AddonRegistry"; +export type { CompilerAddon, CompilerAddons } from "./CompilerAddon"; diff --git a/packages/core/src/compiler/cache/index.ts b/packages/core/src/compiler/cache/index.ts index bf9083cb..09b356da 100644 --- a/packages/core/src/compiler/cache/index.ts +++ b/packages/core/src/compiler/cache/index.ts @@ -4,8 +4,5 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { CacheFile, getCachedName } from "./CacheFile"; -import { FileCache } from "./FileCache"; - -export type { CacheFile }; -export { getCachedName, FileCache }; +export { getCachedName, type CacheFile } from "./CacheFile"; +export { FileCache } from "./FileCache"; diff --git a/packages/core/src/compiler/compilation/index.ts b/packages/core/src/compiler/compilation/index.ts index 61a89de4..f69ffb4c 100644 --- a/packages/core/src/compiler/compilation/index.ts +++ b/packages/core/src/compiler/compilation/index.ts @@ -4,8 +4,6 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { CompilationContext } from "./CompilationContext"; -import { CompilationHost } from "./CompilationHost"; -import { createSharedHost } from "./shared-host"; - -export { createSharedHost, CompilationContext, CompilationHost }; +export { CompilationContext, type CompilationContextOptions } from "./CompilationContext"; +export { CompilationHost } from "./CompilationHost"; +export { createSharedHost } from "./shared-host"; diff --git a/packages/core/src/compiler/config/index.ts b/packages/core/src/compiler/config/index.ts index debcf610..2226c390 100644 --- a/packages/core/src/compiler/config/index.ts +++ b/packages/core/src/compiler/config/index.ts @@ -4,10 +4,7 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import type { CompilationConfig } from "./CompilationConfig"; -import { resolveCompilationConfig, updateCompilerOptions } from "./resolve-compiler-config"; -import { resolveProjectConfig } from "./resolve-project-config"; -import { resolveTargets } from "./resolve-targets"; - -export { resolveProjectConfig, resolveCompilationConfig, resolveTargets, updateCompilerOptions }; -export type { CompilationConfig }; +export type { CompilationConfig } from "./CompilationConfig"; +export { resolveCompilationConfig, updateCompilerOptions } from "./resolve-compiler-config"; +export { resolveProjectConfig } from "./resolve-project-config"; +export { resolveTargets } from "./resolve-targets"; diff --git a/packages/core/src/compiler/index.ts b/packages/core/src/compiler/index.ts index 23beae97..d4648754 100644 --- a/packages/core/src/compiler/index.ts +++ b/packages/core/src/compiler/index.ts @@ -4,15 +4,12 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import type { CompileFragment } from "./Compiler"; -import { Compiler } from "./Compiler"; -import type { CompilerOptions } from "./CompilerOptions"; -import { DefaultReporter } from "./DefaultReporter"; -import { NoReporter } from "./NoReporter"; -import { tsDefaults, tsLibDefaults } from "./defaults"; - +export { Compiler } from "./Compiler"; +export type { CompileFragment } from "./Compiler"; +export type { CompilerOptions } from "./CompilerOptions"; +export { DefaultReporter } from "./DefaultReporter"; +export { NoReporter } from "./NoReporter"; export * from "./addons"; export * from "./compilation"; export * from "./config"; -export { Compiler, DefaultReporter, NoReporter, tsDefaults, tsLibDefaults }; -export type { CompileFragment, CompilerOptions }; +export { tsDefaults, tsLibDefaults } from "./defaults"; diff --git a/packages/core/src/editing/index.ts b/packages/core/src/editing/index.ts index df549ab0..16ef3014 100644 --- a/packages/core/src/editing/index.ts +++ b/packages/core/src/editing/index.ts @@ -4,6 +4,4 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { typecheck } from "./edit-check"; - -export { typecheck }; +export { typecheck } from "./edit-check"; diff --git a/packages/core/src/environment/index.ts b/packages/core/src/environment/index.ts index 4bb82578..da577066 100644 --- a/packages/core/src/environment/index.ts +++ b/packages/core/src/environment/index.ts @@ -4,25 +4,8 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { createBrowserSystem } from "./browser-system"; -import { createCompileHost, createWatchHost, injectTransformers } from "./compile-service"; -import { createLanguageService, createLanguageServiceHost } from "./language-service"; -import { createSystem, createVersionedFile, createVersionedFiles, getVersionedFile, isNodeJs, readFiles, recursiveFindByFilter } from "./system"; -import type { VersionedFile } from "./VersionedFile"; - -export { - createBrowserSystem, - createCompileHost, - createLanguageService, - createLanguageServiceHost, - createVersionedFile, - createVersionedFiles, - createSystem, - createWatchHost, - getVersionedFile, - injectTransformers, - isNodeJs, - readFiles, - recursiveFindByFilter, -}; -export type { VersionedFile }; +export type { VersionedFile } from "./VersionedFile"; +export { createBrowserSystem } from "./browser-system"; +export { createCompileHost, createWatchHost, injectTransformers } from "./compile-service"; +export { createLanguageService, createLanguageServiceHost } from "./language-service"; +export { createSystem, createVersionedFile, createVersionedFiles, getVersionedFile, isNodeJs, readFiles, recursiveFindByFilter } from "./system"; diff --git a/packages/testing/src/index.ts b/packages/testing/src/index.ts index dc244e53..5ca24563 100644 --- a/packages/testing/src/index.ts +++ b/packages/testing/src/index.ts @@ -4,9 +4,9 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -export * from "./ReporterMock"; -export * from "./compile-options"; -export * from "./compile-system"; -export * from "./fusion-fs"; -export * from "./tsLibMocks"; +export { ReporterMock } from "./ReporterMock"; export * from "./compilation"; +export { compileOptions } from "./compile-options"; +export { compileSystem, type CompileSystem, type CompileSystemOptions } from "./compile-system"; +export { createFs, resetFs } from "./fusion-fs"; +export { tsLibMocks } from "./tsLibMocks"; diff --git a/packages/webpack/src/index.ts b/packages/webpack/src/index.ts index 60ff3268..f5752509 100644 --- a/packages/webpack/src/index.ts +++ b/packages/webpack/src/index.ts @@ -5,33 +5,7 @@ * --------------------------------------------------------------------------------------------- */ -import { LoaderContext } from "webpack"; -import { initializeInstance, setInstanceInCache } from "./instance-cache"; -import { getLoaderOptions, PluginOptions } from "./loader-options"; -import { processResultAndFinish } from "./result-handling"; -import { TsCompiler } from "./TsCompiler"; - -function loader(this: LoaderContext): void { - this.cacheable && this.cacheable(); - const loaderOptions = getLoaderOptions(this); - const instance = initializeInstance(this, loaderOptions, (path: string) => { - this.addDependency(path); - }); - const fragment = buildTargets(instance, this.resourcePath); - - this.version = instance.version; - - setInstanceInCache(this._compiler, this, instance); - - processResultAndFinish(this, fragment, instance.targets); -} - -const buildTargets = (compiler: TsCompiler, resourcePath: string) => { - return compiler.build(resourcePath); -}; - -export default loader; - -export { Compiler, createBrowserSystem, DefaultReporter, getVersionedFile, NoReporter } from "@quatico/websmith-core"; -export { Upath as uPath } from "./Upath"; +export { Compiler, DefaultReporter, NoReporter, createBrowserSystem, getVersionedFile } from "@quatico/websmith-core"; export type { CompilerOptions } from "@quatico/websmith-core"; +export { Upath as uPath } from "./Upath"; +export { loader as default } from "./loader"; diff --git a/packages/webpack/src/loader-options.ts b/packages/webpack/src/loader-options.ts index 0b1266c4..08d04f25 100644 --- a/packages/webpack/src/loader-options.ts +++ b/packages/webpack/src/loader-options.ts @@ -7,7 +7,7 @@ import { LoaderContext, WebpackError } from "webpack"; import { DEFAULTS } from "./options"; -import { Upath } from "./Upath"; +import { Upath as uPath } from "./Upath"; export interface PluginArguments { addons?: string; @@ -33,7 +33,7 @@ export const getLoaderOptions = (loader: LoaderContext): PluginOp ...options, ...(loader._module && loader._module.addWarning && { warn: (err: WebpackError) => loader._module!.addWarning(err) }), ...(loader._module && loader._module.addError && { error: (err: WebpackError) => loader._module!.addError(err) }), - config: Upath.resolve(options.config ?? DEFAULTS.config), + config: uPath.resolve(options.config ?? DEFAULTS.config), transpileOnly: options.transpileOnly ?? false, webpackTarget: options.webpackTarget ?? "*", }; diff --git a/packages/webpack/src/loader.ts b/packages/webpack/src/loader.ts new file mode 100644 index 00000000..d5187fe7 --- /dev/null +++ b/packages/webpack/src/loader.ts @@ -0,0 +1,23 @@ +import { LoaderContext } from "webpack"; +import { initializeInstance, setInstanceInCache } from "./instance-cache"; +import { getLoaderOptions, PluginOptions } from "./loader-options"; +import { processResultAndFinish } from "./result-handling"; +import { TsCompiler } from "./TsCompiler"; + +export function loader(this: LoaderContext): void { + this.cacheable && this.cacheable(); + const loaderOptions = getLoaderOptions(this); + const instance = initializeInstance(this, loaderOptions, (path: string) => { + this.addDependency(path); + }); + const fragment = buildTargets(instance, this.resourcePath); + + this.version = instance.version; + + setInstanceInCache(this._compiler, this, instance); + + processResultAndFinish(this, fragment, instance.targets); +} +const buildTargets = (compiler: TsCompiler, resourcePath: string) => { + return compiler.build(resourcePath); +}; From ac4d58dae73eaf8b1f81868f2aef884951851a24 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Mon, 6 May 2024 20:53:48 +0200 Subject: [PATCH 44/52] e Fixes debug config for webpack e2e tests --- .vscode/launch.json | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 2e5174e9..4c1717f7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,14 +9,7 @@ "name": "vscode-jest-tests", "request": "launch", "program": "${workspaceFolder}/node_modules/.bin/jest", - "args": [ - "--runInBand", - "--watchAll=false", - "--testNamePattern", - "${jest.testNamePattern}", - "--runTestsByPath", - "${jest.testFile}" - ], + "args": ["--runInBand", "--watchAll=false", "--testNamePattern", "${jest.testNamePattern}", "--runTestsByPath", "${jest.testFile}"], "cwd": "${workspaceFolder}", "console": "integratedTerminal", "internalConsoleOptions": "neverOpen", @@ -32,8 +25,8 @@ "console": "integratedTerminal", "internalConsoleOptions": "neverOpen", "program": "${workspaceFolder}/node_modules/.bin/jest", - "cwd": "${workspaceFolder}/packages/webpack", - "args": ["-c", "${workspaceFolder}/packages/webpack/jest.e2e.config.js", "--runInBand", "-o", "--all"], + "cwd": "${workspaceFolder}/packages/webpack-test", + "args": ["-c", "${workspaceFolder}/packages/webpack-test/jest.config.js", "--runInBand", "-o", "--all"], "windows": { "program": "${workspaceFolder}/node_modules/jest/bin/jest" } From dcf05bc9aab91905848654ad3d5a1a626c1b88fe Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Mon, 6 May 2024 20:54:39 +0200 Subject: [PATCH 45/52] r Tidy exports in index files --- packages/core/src/compiler/addons/index.ts | 4 ++-- packages/webpack-test/__data__/module-test/src/model/index.ts | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/core/src/compiler/addons/index.ts b/packages/core/src/compiler/addons/index.ts index 673df913..d167c536 100644 --- a/packages/core/src/compiler/addons/index.ts +++ b/packages/core/src/compiler/addons/index.ts @@ -4,6 +4,6 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ +export { AddonRegistry, type AddonConfig } from "./AddonRegistry"; +export { compilerAddons, type CompilerAddon, type CompilerAddons } from "./CompilerAddon"; export { createResolver } from "./addon-resolver"; -export { AddonRegistry } from "./AddonRegistry"; -export type { CompilerAddon, CompilerAddons } from "./CompilerAddon"; diff --git a/packages/webpack-test/__data__/module-test/src/model/index.ts b/packages/webpack-test/__data__/module-test/src/model/index.ts index 37195dc5..2788e98c 100644 --- a/packages/webpack-test/__data__/module-test/src/model/index.ts +++ b/packages/webpack-test/__data__/module-test/src/model/index.ts @@ -1,3 +1 @@ -import { createMessage } from "./create-message"; - -export { createMessage }; +export { createMessage } from "./create-message"; From db355dea943fdfd455ecef699c4734bdbc4bc5d2 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Mon, 6 May 2024 20:55:31 +0200 Subject: [PATCH 46/52] B!! Replaces remaining usages of AddonRegistry in config options --- packages/core/test/compile-options.ts | 3 +-- packages/webpack/src/TsCompiler.spec.ts | 13 +++++-------- packages/webpack/src/TsCompiler.ts | 11 +++++++---- packages/webpack/src/instance-cache.spec.ts | 9 ++++----- packages/webpack/src/options.ts | 9 +-------- 5 files changed, 18 insertions(+), 27 deletions(-) diff --git a/packages/core/test/compile-options.ts b/packages/core/test/compile-options.ts index a468bee5..8a7af4b3 100644 --- a/packages/core/test/compile-options.ts +++ b/packages/core/test/compile-options.ts @@ -5,7 +5,7 @@ * --------------------------------------------------------------------------------------------- */ import ts from "typescript"; -import { AddonRegistry, type CompilerOptions } from "../src/compiler"; +import { type CompilerOptions } from "../src/compiler"; import { ReporterMock } from "./ReporterMock"; export const compileOptions = ( @@ -14,7 +14,6 @@ export const compileOptions = ( ): CompilerOptions => { const reporter = new ReporterMock(system); return { - addons: new AddonRegistry({ addonsDir: "./addons", reporter, system }), buildDir: "./src", reporter, debug: false, diff --git a/packages/webpack/src/TsCompiler.spec.ts b/packages/webpack/src/TsCompiler.spec.ts index f5229704..9b63a204 100644 --- a/packages/webpack/src/TsCompiler.spec.ts +++ b/packages/webpack/src/TsCompiler.spec.ts @@ -6,12 +6,12 @@ */ import { Reporter } from "@quatico/websmith-api"; -import { AddonRegistry, CompileFragment, CompilerOptions, NoReporter } from "@quatico/websmith-core"; +import { CompileFragment, CompilerOptions, NoReporter } from "@quatico/websmith-core"; import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs"; import { dirname, resolve } from "path"; import ts from "typescript"; -import { PluginOptions } from "./loader-options"; import { TsCompiler } from "./TsCompiler"; +import { PluginOptions } from "./loader-options"; class TestCompiler extends TsCompiler { private sys: ts.System | undefined; @@ -52,7 +52,6 @@ describe("TsCompiler", () => { beforeEach(() => { testObj = new TestCompiler( { - addons: new AddonRegistry({ addonsDir: "./addons", reporter: reporter, system: ts.sys }), buildDir: resolve("./__TEMP__"), project: { declaration: true, target: 99, noEmitOnError: true }, reporter, @@ -63,7 +62,7 @@ describe("TsCompiler", () => { transpileOnly: false, watch: false, }, - undefined + { addonsDir: "./addons", config: "./websmith.config.json" } ); }); @@ -113,7 +112,6 @@ describe("Transpilation", () => { const reporter = new NoReporter(); testObj = new TestCompiler( { - addons: new AddonRegistry({ addonsDir: "./addons", reporter, system: ts.sys }), buildDir: resolve("./__TEMP__"), project: { declaration: true, target: 99, noEmitOnError: true }, reporter, @@ -124,7 +122,7 @@ describe("Transpilation", () => { transpileOnly: false, watch: false, }, - undefined + { addonsDir: "./addons", config: "./websmith.config.json" } ); const actual = testObj.build(expected); @@ -142,7 +140,6 @@ describe("Transpilation", () => { const reporter = new NoReporter(); testObj = new TestCompiler( { - addons: new AddonRegistry({ addonsDir: "./addons", reporter, system: ts.sys }), buildDir: resolve("./__TEMP__"), config: { configFilePath: resolve("./__TEMP__/websmith.config.json"), @@ -160,7 +157,7 @@ describe("Transpilation", () => { transpileOnly: false, watch: false, }, - { config: resolve("__TEMP__", "websmith.config.json"), webpackTarget: "fragment" } + { config: resolve("__TEMP__", "websmith.config.json"), webpackTarget: "fragment", addonsDir: "./addons" } ); const actual = testObj.build(expected); diff --git a/packages/webpack/src/TsCompiler.ts b/packages/webpack/src/TsCompiler.ts index f3096789..ed74a473 100644 --- a/packages/webpack/src/TsCompiler.ts +++ b/packages/webpack/src/TsCompiler.ts @@ -22,14 +22,16 @@ export class TsCompiler extends Compiler { super( options, ts.sys, - pluginOptions.addonsDir + options.config?.addonsDir ?? pluginOptions.addonsDir ? new AddonRegistry({ addons: - (pluginOptions.addons ?? "") + options.config?.addons ?? + pluginOptions.addons ?.split(",") .map(it => it.trim()) - .filter(it => it.length > 0) ?? [], - addonsDir: pluginOptions.addonsDir, + .filter(it => it.length > 0) ?? + [], + addonsDir: options.config?.addonsDir ?? pluginOptions.addonsDir ?? "./addons", reporter: options.reporter, system: ts.sys, }) @@ -37,6 +39,7 @@ export class TsCompiler extends Compiler { dependencyCallback ); this.pluginConfig = pluginOptions; + this.getAddonRegistry()?.refresh(); super.createTargetContextsIfNecessary(); this.targets = options.targets; this.webpackTarget = this.getFragmentTarget(pluginOptions.webpackTarget!); diff --git a/packages/webpack/src/instance-cache.spec.ts b/packages/webpack/src/instance-cache.spec.ts index 3eda840f..5ec48a20 100644 --- a/packages/webpack/src/instance-cache.spec.ts +++ b/packages/webpack/src/instance-cache.spec.ts @@ -4,14 +4,13 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. * --------------------------------------------------------------------------------------------- */ -import { AddonRegistry, NoReporter } from "@quatico/websmith-core"; +import { NoReporter } from "@quatico/websmith-core"; import { randomUUID } from "crypto"; import { rmSync } from "fs"; import { join } from "path"; -import ts from "typescript"; import webpack, { Compilation, Compiler, LoaderContext } from "webpack"; -import { getCacheName, getInstanceFromCache, initializeInstance, setInstanceInCache } from "./instance-cache"; import { TsCompiler } from "./TsCompiler"; +import { getCacheName, getInstanceFromCache, initializeInstance, setInstanceInCache } from "./instance-cache"; let compiler: Compiler; let context: LoaderContext; @@ -25,7 +24,6 @@ beforeEach(() => { const reporter = new NoReporter(); tsCompiler = new TsCompiler( { - addons: new AddonRegistry({ addonsDir: "./addons", reporter: reporter, system: ts.sys }), buildDir: "./src", project: {}, reporter, @@ -36,7 +34,8 @@ beforeEach(() => { transpileOnly: false, watch: false, }, - () => undefined + () => undefined, + { addonsDir: "./addons", config: "./websmith.config.json" } ); }); diff --git a/packages/webpack/src/options.ts b/packages/webpack/src/options.ts index 04d95c00..8e8705c3 100644 --- a/packages/webpack/src/options.ts +++ b/packages/webpack/src/options.ts @@ -13,7 +13,7 @@ import { resolveProjectConfig as resolveTsConfig, updateCompilerOptions, } from "@quatico/websmith-core"; -import { dirname, join } from "path"; +import { dirname } from "path"; import ts from "typescript"; import { PluginOptions } from "./loader-options"; @@ -46,13 +46,6 @@ export const createOptions = (args: Partial, reporter: Reporter = } } - args = { - ...args, - ...(args.addonsDir && - projectDirectory && - args.addonsDir !== DEFAULTS.addonsDir && { addonsDir: system.resolvePath(join(projectDirectory, args.addonsDir)) }), - }; - return { buildDir: args.buildDir ?? system.getCurrentDirectory(), config: compilationConfig, From f5a319b7fa60214c81eee665f2e39fd596218aed Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Mon, 6 May 2024 23:38:59 +0200 Subject: [PATCH 47/52] B Fixes in-memory compilation of addons from external source folder + Add importDir as sourceFolder for addons to compile --- .../core/src/compiler/addons/AddonRegistry.ts | 4 +- .../core/src/compiler/addons/CompilerAddon.ts | 2 - .../testing/src/compilation/copy-directory.ts | 5 ++- .../testing/src/compilation/environment.ts | 37 +++++++++++++------ 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/packages/core/src/compiler/addons/AddonRegistry.ts b/packages/core/src/compiler/addons/AddonRegistry.ts index 83fecaf3..d0fee365 100644 --- a/packages/core/src/compiler/addons/AddonRegistry.ts +++ b/packages/core/src/compiler/addons/AddonRegistry.ts @@ -97,7 +97,7 @@ export class AddonRegistry { return; } const addon = createAddon(system, filePath, addonName); - if (addon.activate) { + if (typeof addon.activate === "function") { map.set(addonName, addon); } else { reporter.reportDiagnostic(new WarnMessage(`No "activate" function found for addon "${addonName}" in "${addonsDir}".`)); @@ -108,7 +108,7 @@ export class AddonRegistry { } } -const createAddon = (system: ts.System, filePath: string, addonName: string) => { +const createAddon = (system: ts.System, filePath: string, addonName: string): CompilerAddon => { const importPath = getImportPath(system, filePath); // eslint-disable-next-line @typescript-eslint/no-var-requires return { getName: () => addonName, activate: require(importPath).activate }; diff --git a/packages/core/src/compiler/addons/CompilerAddon.ts b/packages/core/src/compiler/addons/CompilerAddon.ts index 20c3b4f8..8d157212 100644 --- a/packages/core/src/compiler/addons/CompilerAddon.ts +++ b/packages/core/src/compiler/addons/CompilerAddon.ts @@ -8,8 +8,6 @@ import { AddonContext } from "@quatico/websmith-api"; export interface CompilerAddon { - // FIXME: We need to add the sourceDir of the addon - sourceDir?: string; getName: () => string; activate: (context: AddonContext) => void; } diff --git a/packages/testing/src/compilation/copy-directory.ts b/packages/testing/src/compilation/copy-directory.ts index 3c299c7e..824e1065 100644 --- a/packages/testing/src/compilation/copy-directory.ts +++ b/packages/testing/src/compilation/copy-directory.ts @@ -46,12 +46,13 @@ export const copyDirectory = (source: SourcePath, target: TargetPath) => { }; const copyFile = (source: SourceFilePath, target: TargetPath) => { - const { system: srcSystem, path: srcPath, subDirName, kind } = source; + const { system: srcSystem, path: srcPath, subDirName } = source; const fileContent = srcSystem.readFile(srcPath); if (typeof fileContent === "string") { // Create a new file with the same path relative to `buildDir` - const targetPath = join(target.path, srcPath.substring(srcPath.indexOf(subDirName) + (kind === "project" ? subDirName.length + 1 : 0))); + const filePath = srcPath.substring(srcPath.indexOf(subDirName) + subDirName.length + 1); + const targetPath = join(target.path, filePath); target.system.writeFile(targetPath, fileContent); } }; diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index b3132e42..ad34951e 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -5,8 +5,8 @@ * --------------------------------------------------------------------------------------------- */ import { - AddonRegistry, AddonConfig, + AddonRegistry, Compiler, CompilerAddons, DefaultReporter, @@ -16,6 +16,7 @@ import { type CompilerOptions, } from "@quatico/websmith-core"; import { rmSync } from "fs"; +import { Module } from "module"; import { basename, dirname, extname, isAbsolute, join } from "path"; import requireFromString from "require-from-string"; import ts from "typescript"; @@ -150,6 +151,7 @@ export class CompilationEnv { return this; } const addonTargetPath = join(this.addons.getAddonsDir(), addonName); + let addonImportDir = join(this.rootDir, addonName); if (!this.system.directoryExists(addonTargetPath)) { this.system.createDirectory(addonTargetPath); @@ -160,10 +162,11 @@ export class CompilationEnv { const addonsSourceDir = resolveProjectPath(this.system, this.rootDir, join(addonSource ?? DEFAULT_ADDONS_SOURCE_DIR, addonName)); const sourceFs = this.system.directoryExists(addonsSourceDir) ? this.system : ts.sys; copyDirectory({ system: sourceFs, path: addonsSourceDir, kind: "addons" }, { system: this.system, path: addonTargetPath }); + addonImportDir = addonsSourceDir; } if (this.addons) { - this.compileAddons(this.addons.getAddonsDir()); + this.compileAddons(addonImportDir, this.addons.getAddonsDir()); this.addons.refresh(); } return this; @@ -177,7 +180,7 @@ export class CompilationEnv { addonNames.forEach(addon => { copyDirectory({ system: sourceFs, path: join(addonsSourceDirPath, addon), kind: "addons" }, { system: this.system, path: addonsDir }); }); - this.compileAddons(addonsDir); + this.compileAddons(addonsSourceDirPath, addonsDir); this.addons?.refresh(); } return this; @@ -297,9 +300,9 @@ export class CompilationEnv { }, {}); } - private compileAddons(addonsDir: string) { + private compileAddons(addonsSourceDir: string, addonsTargetDir: string) { const addonsToCompile = this.system - .readDirectory(addonsDir) + .readDirectory(addonsTargetDir) .filter(isSourceFile) .map(it => dirname(it)); @@ -309,7 +312,12 @@ export class CompilationEnv { ...compileOptions(this.system, { buildDir: curDir, }), - project: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES5, esModuleInterop: true }, + project: { + module: ts.ModuleKind.CommonJS, + target: ts.ScriptTarget.ES5, + esModuleInterop: true, + moduleResolution: ts.ModuleResolutionKind.NodeNext, + }, tsconfig: { fileNames: this.system.readDirectory(curDir).filter(isSourceFile), options: {}, errors: [] }, }, this.system @@ -318,14 +326,19 @@ export class CompilationEnv { if (this.virtual) { this.system - .readDirectory(addonsDir, [".js", ".jsx"]) - .filter(filePath => basename(filePath, extname(filePath)).toLocaleLowerCase() === "addon") - .map(resolvedPath => this.system.resolvePath(resolvedPath)) + .readDirectory(addonsTargetDir, [".js", ".jsx"]) + .map(filePath => this.system.resolvePath(filePath)) .forEach(resolvedPath => { jest.mock( - extname(resolvedPath).match(/^(?!.*\.d\.tsx?$).*\.[j]sx?$/g) ? resolvedPath.replace(extname(resolvedPath), "") : resolvedPath, - // FIXME: replace __dirname with the actual sourceDir of the addon - () => requireFromString(this.system.readFile(resolvedPath)!, __dirname), + basename(resolvedPath, extname(resolvedPath)) === "addon" + ? resolvedPath.replace(extname(resolvedPath), "") + : `./${basename(resolvedPath, extname(resolvedPath))}`, + () => + requireFromString(this.system.readFile(resolvedPath)!, resolvedPath, { + prependPaths: [dirname(resolvedPath), addonsTargetDir], + // @ts-expect-error - nodeModulePaths is not part of the original object + appendPaths: Module._nodeModulePaths(dirname(addonsSourceDir)), + }), { virtual: true } ); }); From e541b31c590fa06fcc4a32da3637270aba48b336 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Mon, 6 May 2024 23:39:26 +0200 Subject: [PATCH 48/52] t Adds e2e tests for remaining example addons --- packages/examples/jest.config.js | 2 ++ .../examples/tests/example-generator.test.ts | 2 +- .../tests/export-yaml-generator.test.ts | 21 ++++++++---- .../tests/foobar-replace-processor.test.ts | 33 +++++++++++++++++++ .../tests/foobar-replace-transformer.test.ts | 33 +++++++++++++++++++ 5 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 packages/examples/tests/foobar-replace-processor.test.ts create mode 100644 packages/examples/tests/foobar-replace-transformer.test.ts diff --git a/packages/examples/jest.config.js b/packages/examples/jest.config.js index a963d490..76b919e5 100644 --- a/packages/examples/jest.config.js +++ b/packages/examples/jest.config.js @@ -25,4 +25,6 @@ module.exports = { }, ], }, + resetMocks: true, + restoreMocks: true, }; diff --git a/packages/examples/tests/example-generator.test.ts b/packages/examples/tests/example-generator.test.ts index 5925655d..038cde25 100644 --- a/packages/examples/tests/example-generator.test.ts +++ b/packages/examples/tests/example-generator.test.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ import { join } from "path"; -import { compilationEnv, type CompilationEnv } from "../../testing/lib"; +import { compilationEnv, type CompilationEnv } from "@quatico/websmith-testing"; describe("example-generator", () => { let testObj: CompilationEnv; diff --git a/packages/examples/tests/export-yaml-generator.test.ts b/packages/examples/tests/export-yaml-generator.test.ts index 3bb9b6f5..65b2eda9 100644 --- a/packages/examples/tests/export-yaml-generator.test.ts +++ b/packages/examples/tests/export-yaml-generator.test.ts @@ -4,18 +4,21 @@ import { compilationEnv, type CompilationEnv } from "@quatico/websmith-testing"; import { join } from "path"; -// FIXME: This test is failing because the virtual mock for this addon needs the actual sourceDir -describe.skip("export-yaml-generator", () => { +describe("export-yaml-generator", () => { let testObj: CompilationEnv; beforeAll(() => { - testObj = compilationEnv("./__TEST__").addAddon("export-yaml-generator", join(__dirname, "../addons")); + testObj = compilationEnv("./__TEST__", { compilerOptions: { project: { outDir: "dist" } }, virtual: false }).addAddon( + "export-yaml-generator", + join(__dirname, "../addons") + ); }); afterEach(() => { - testObj.cleanUp("project"); + testObj.cleanUp(); }); - it("should create additional input files and add them to compilation", () => { + // TODO: BUG in addon? The test fails as the addon does not report on exported classes. + it.skip("should create additional input files and add them to compilation", () => { testObj .addProjectFromSource({ "bar.ts": `console.log("Hello, Bar!");`, @@ -23,8 +26,12 @@ describe.skip("export-yaml-generator", () => { }) .compile(); - const actual = testObj.getCompiledFiles().getPaths(); + const actual = testObj + .getCompiledFiles() + .getPaths() + .map(it => it.substring(it.indexOf("/__TEST__"))); - expect(actual).toEqual(["/__TEST__/dist/bar.js", "/__TEST__/dist/foo.js", "/__TEST__/dist/foo-added.js"]); + expect(actual).toEqual(["/__TEST__/dist/bar.js", "/__TEST__/dist/foo.js", "/__TEST__/dist/output.yaml"]); + expect(testObj.getCompiledFile("output.yaml")?.getContent()).toEqual(expect.stringContaining("exports: [Foo]")); }); }); diff --git a/packages/examples/tests/foobar-replace-processor.test.ts b/packages/examples/tests/foobar-replace-processor.test.ts new file mode 100644 index 00000000..ad8cfbe4 --- /dev/null +++ b/packages/examples/tests/foobar-replace-processor.test.ts @@ -0,0 +1,33 @@ +import { CompilationEnv, compilationEnv } from "@quatico/websmith-testing"; +import { join } from "path"; + +describe("foobar-replace-processor", () => { + let testObj: CompilationEnv; + beforeAll(() => { + testObj = compilationEnv("./__TEST__", { compilerOptions: { project: { outDir: "dist" } }, virtual: false }).addAddon( + "foobar-replace-processor", + join(__dirname, "../addons") + ); + }); + + afterEach(() => { + testObj.cleanUp(); + }); + + it("should replace 'foo' with 'bar' in the output files", () => { + testObj + .addProjectFromSource({ + "bar.ts": `console.log("Hello, Bar!");`, + "foo.ts": `export class Foobar {}`, + }) + .compile(); + + const actual = testObj + .getCompiledFiles() + .getPaths() + .map(it => it.substring(it.indexOf("/__TEST__"))); + + expect(actual).toEqual(["/__TEST__/dist/bar.js", "/__TEST__/dist/foo.js"]); + expect(testObj.getCompiledFile("foo.js")?.getContent()).toEqual(expect.stringContaining("export class barfoo {")); + }); +}); diff --git a/packages/examples/tests/foobar-replace-transformer.test.ts b/packages/examples/tests/foobar-replace-transformer.test.ts new file mode 100644 index 00000000..e187903e --- /dev/null +++ b/packages/examples/tests/foobar-replace-transformer.test.ts @@ -0,0 +1,33 @@ +import { CompilationEnv, compilationEnv } from "@quatico/websmith-testing"; +import { join } from "path"; + +describe("foobar-replace-transformer", () => { + let testObj: CompilationEnv; + beforeAll(() => { + testObj = compilationEnv("./__TEST__", { compilerOptions: { project: { outDir: "dist" } }, virtual: false }).addAddon( + "foobar-replace-transformer", + join(__dirname, "../addons") + ); + }); + + afterEach(() => { + testObj.cleanUp(); + }); + + it("should replace 'foo' with 'bar' in the output files", () => { + testObj + .addProjectFromSource({ + "bar.ts": `console.log("Hello, Bar!");`, + "foo.ts": `export class FooBar {}`, + }) + .compile(); + + const actual = testObj + .getCompiledFiles() + .getPaths() + .map(it => it.substring(it.indexOf("/__TEST__"))); + + expect(actual).toEqual(["/__TEST__/dist/bar.js", "/__TEST__/dist/foo.js"]); + expect(testObj.getCompiledFile("foo.js")?.getContent()).toEqual(expect.stringContaining("export class barfoo")); + }); +}); From 15497dbdd4929e7d269e2e8c2d01d191f0c93076 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Tue, 7 May 2024 10:12:45 +0200 Subject: [PATCH 49/52] B Fixes an issue where projects from custom source paths are copied into a separate directory in the buildDir --- packages/test/src/bar-addon.test.ts | 2 +- .../testing/src/compilation/copy-directory.ts | 15 +++++++++++--- .../src/compilation/environment.spec.ts | 14 ++++++------- .../testing/src/compilation/environment.ts | 20 +++++++++---------- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/packages/test/src/bar-addon.test.ts b/packages/test/src/bar-addon.test.ts index 46b0961c..76162cbd 100644 --- a/packages/test/src/bar-addon.test.ts +++ b/packages/test/src/bar-addon.test.ts @@ -11,7 +11,7 @@ describe("test-project-foo", () => { it("should install addon successfully", () => { const testObj = compilationEnv("__TEST__").addAddon("foo-addon", join(__dirname, "../test-data/addons")); - const actual = testObj.getActiveAddons().map(it => it.getName()); + const actual = testObj.getActiveAddons().getNames(); expect(actual).toContain("foo-addon"); }); diff --git a/packages/testing/src/compilation/copy-directory.ts b/packages/testing/src/compilation/copy-directory.ts index 824e1065..bae2afc5 100644 --- a/packages/testing/src/compilation/copy-directory.ts +++ b/packages/testing/src/compilation/copy-directory.ts @@ -46,12 +46,21 @@ export const copyDirectory = (source: SourcePath, target: TargetPath) => { }; const copyFile = (source: SourceFilePath, target: TargetPath) => { - const { system: srcSystem, path: srcPath, subDirName } = source; + const { system: srcSystem, path: srcPath, subDirName, kind } = source; const fileContent = srcSystem.readFile(srcPath); if (typeof fileContent === "string") { - // Create a new file with the same path relative to `buildDir` - const filePath = srcPath.substring(srcPath.indexOf(subDirName) + subDirName.length + 1); + let filePath; + if (kind === "addons") { + // TODO: target file path seems somewhat off, it sometimes includes the subDirName twice when addons are copied + filePath = srcPath.substring( + // Don't add the subDirName to the target path if it's already included + srcPath.indexOf(subDirName) + (kind === "addons" && target.path.includes(subDirName) ? subDirName.length + 1 : 0) + ); + } else { + // kind === "project" + filePath = srcPath.substring(srcPath.indexOf(subDirName) + subDirName.length + 1); + } const targetPath = join(target.path, filePath); target.system.writeFile(targetPath, fileContent); } diff --git a/packages/testing/src/compilation/environment.spec.ts b/packages/testing/src/compilation/environment.spec.ts index 2b7c7126..c3c811b8 100644 --- a/packages/testing/src/compilation/environment.spec.ts +++ b/packages/testing/src/compilation/environment.spec.ts @@ -86,7 +86,7 @@ describe("compilationEnv#addons", () => { it("should yield addon with valid addon source", () => { const testObj = compilationEnv("/target").addAddon("expected-addon", { "addon.ts": `export const activate = () => {};` }); - const actual = testObj.getActiveAddons().map(it => it.getName()); + const actual = testObj.getActiveAddons().getNames(); expect(actual).toEqual(["expected-addon"]); }); @@ -106,7 +106,7 @@ describe("compilationEnv#addons", () => { testObj.addAddon("expected-addon"); - const actual = testObj.getActiveAddons().map(it => it.getName()); + const actual = testObj.getActiveAddons().getNames(); expect(actual).toEqual(["expected-addon"]); }); @@ -118,19 +118,19 @@ describe("compilationEnv#addons", () => { testObj.addAddons(["expected-addon1", "expected-addon2"]); - const actual = testObj.getActiveAddons().map(it => it.getName()); + const actual = testObj.getActiveAddons().getNames(); expect(actual).toEqual(["expected-addon1", "expected-addon2"]); }); it("should yield addons with multiple addons in custom addons path", () => { - const testObj = compilationEnv("/target"); + const testObj = compilationEnv("/target", {}, { addonsDir: "./custom-addons-folder/" }); testObj.getSystem().writeFile("/target/custom-addons-folder/expected-addon1/addon.ts", `export const activate = () => {};`); testObj.getSystem().writeFile("/target/custom-addons-folder/expected-addon2/addon.ts", `export const activate = () => {};`); testObj.addAddons(["expected-addon1", "expected-addon2"], "./custom-addons-folder/"); - const actual = testObj.getActiveAddons().map(it => it.getName()); + const actual = testObj.getActiveAddons().getNames(); expect(actual).toEqual(["expected-addon1", "expected-addon2"]); }); @@ -240,9 +240,9 @@ describe("compilationEnv#projects", () => { testObj.addProjectFromDisk("expected-project", "../custom-projects/"); - const actual = testObj.getProjectFiles(); + const actual = testObj.getProjectFiles().getPaths(); - expect(actual.getPaths()).toEqual(["/target/src/index.ts", "/target/src/target.ts", "/target/tsconfig.json"]); + expect(actual).toEqual(["/target/src/index.ts", "/target/src/target.ts", "/target/tsconfig.json"]); }); it("should yield project and add files with file name", () => { diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index ad34951e..0c717b4f 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -38,7 +38,7 @@ export class CompilationEnv { private virtual: boolean; private addons?: AddonRegistry; - constructor(rootDir?: string, options?: CompilationOptions, addonConfig?: AddonConfig) { + constructor(rootDir?: string, options?: Partial, addonConfig?: Partial) { const { virtual = true, compilerOptions = {}, useCaseSensitiveFileNames } = options ?? {}; this.virtual = virtual; this.system = this.virtual ? createBrowserSystem(undefined, useCaseSensitiveFileNames) : ts.sys; @@ -73,14 +73,13 @@ export class CompilationEnv { ...compilerOptions, }); - if (!addonConfig) { - addonConfig = { - addonsDir: join(this.rootDir, "./addons"), - reporter: new DefaultReporter(this.system), - system: this.system, - }; - } - this.addons = new AddonRegistry(addonConfig); + const registryConfig = { + ...(addonConfig ?? {}), + addonsDir: join(this.rootDir, "./addons"), + reporter: new DefaultReporter(this.system), + system: this.system, + }; + this.addons = new AddonRegistry(registryConfig); if (!this.system.directoryExists(this.addons.getAddonsDir())) { this.system.createDirectory(this.addons.getAddonsDir()); } @@ -220,6 +219,7 @@ export class CompilationEnv { const sourceFs = this.system.directoryExists(projectsSourcePath) ? this.system : ts.sys; copyDirectory( { system: sourceFs, path: join(projectsSourcePath, projectName), kind: "project" }, + // use rootDir as target path because we copy src and other files from project directory { system: this.system, path: this.rootDir } ); this.compilerOptions.tsconfig.fileNames = this.system.readDirectory(this.buildDir).filter(isSourceFile); @@ -410,5 +410,5 @@ const projectFiles = (result: ProjectFile[]): ProjectFiles => { return Object.assign(result, { getPaths: () => result.map(it => it.getPath()), getContents: () => result.map(it => it.getContent()!) }); }; -export const compilationEnv = (rootDir: string, options?: CompilationOptions, addonConfig?: AddonConfig): CompilationEnv => +export const compilationEnv = (rootDir: string, options?: Partial, addonConfig?: Partial): CompilationEnv => new CompilationEnv(rootDir, options, addonConfig); From c620c9c5841be3bfb2d20e7dbffc88a945d4f332 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Tue, 7 May 2024 11:58:38 +0200 Subject: [PATCH 50/52] F Adds initial documentation for testing addon examples --- .../foobar-replace-transformer/addon.ts | 2 +- .../examples/tests/example-generator.test.ts | 16 +- .../tests/foobar-replace-processor.test.ts | 4 + .../tests/foobar-replace-transformer.test.ts | 4 + packages/testing/README.md | 199 +++++++++++++----- 5 files changed, 174 insertions(+), 51 deletions(-) diff --git a/packages/examples/addons/foobar-replace-transformer/addon.ts b/packages/examples/addons/foobar-replace-transformer/addon.ts index 1f0ca2f6..4a1aa178 100644 --- a/packages/examples/addons/foobar-replace-transformer/addon.ts +++ b/packages/examples/addons/foobar-replace-transformer/addon.ts @@ -16,7 +16,7 @@ export const activate = (ctx: AddonContext): void => { * * @returns A TS transformer factory. */ -export const createTransformer = (): ts.TransformerFactory => { +const createTransformer = (): ts.TransformerFactory => { return (ctx: ts.TransformationContext): ts.Transformer => { return (sf: ts.SourceFile): ts.SourceFile => { const visitor = (node: ts.Node): ts.Node => { diff --git a/packages/examples/tests/example-generator.test.ts b/packages/examples/tests/example-generator.test.ts index 038cde25..ba358266 100644 --- a/packages/examples/tests/example-generator.test.ts +++ b/packages/examples/tests/example-generator.test.ts @@ -18,12 +18,26 @@ describe("example-generator", () => { testObj .addProjectFromSource({ "bar.ts": `console.log("Hello, Bar!");`, - "foo.ts": `export class Foo {}`, + "foo.ts": `export class Foo { + constructor(public value: T) { + console.log("Hello, Foo!", JSON.stringify(value)); + } + }`, }) .compile(); const actual = testObj.getCompiledFiles().getPaths(); expect(actual).toEqual(["/__TEST__/dist/bar.js", "/__TEST__/dist/foo.js", "/__TEST__/dist/foo-added.js"]); + expect(testObj.getCompiledFile("foo.js")?.getContent()).toMatchInlineSnapshot(` + "export class Foo { + value; + constructor(value) { + this.value = value; + console.log("Hello, Foo!", JSON.stringify(value)); + } + } + " + `); }); }); diff --git a/packages/examples/tests/foobar-replace-processor.test.ts b/packages/examples/tests/foobar-replace-processor.test.ts index ad8cfbe4..36594cda 100644 --- a/packages/examples/tests/foobar-replace-processor.test.ts +++ b/packages/examples/tests/foobar-replace-processor.test.ts @@ -11,6 +11,10 @@ describe("foobar-replace-processor", () => { }); afterEach(() => { + testObj.cleanUp("project"); + }); + + afterAll(() => { testObj.cleanUp(); }); diff --git a/packages/examples/tests/foobar-replace-transformer.test.ts b/packages/examples/tests/foobar-replace-transformer.test.ts index e187903e..88519c09 100644 --- a/packages/examples/tests/foobar-replace-transformer.test.ts +++ b/packages/examples/tests/foobar-replace-transformer.test.ts @@ -11,6 +11,10 @@ describe("foobar-replace-transformer", () => { }); afterEach(() => { + testObj.cleanUp("project"); + }); + + afterAll(() => { testObj.cleanUp(); }); diff --git a/packages/testing/README.md b/packages/testing/README.md index 3c69d1ba..ea814473 100644 --- a/packages/testing/README.md +++ b/packages/testing/README.md @@ -6,15 +6,30 @@ --> # Websmith Testing API -This library provides a simple API for testing Websmith addons in your project. +This library strives to simplify compiler testing significantly. Setup the typescript compiler, customize projects settings, add custom compiler addons, and compile various projects within 5 lines of code. Use Unit Test style setup and assertions with Jest. Compile projects from the filesystem or from virtual file content and compare compiled results expected from the filesystem, or virtual snapshots. -## Installation +The library can run tests, with + +* Standard Jest test runner configuration and API +* Compiler addons written in TypeScript directly (no need to compile them upfront) +* A virtual file system, compile from and to memory, no need to write files to disk +* Mixed project and addon sources from the filesystem and virtual file content +* Navigate the project and compiled files with a simple API +* Compare compiled file contents with expected from the filesystem, or virtual snapshots + +The library is designed to be used with Jest, but it can be used with any other test framework when the actual file system is used. + +## 1 Installation and Setup + +Install the library in your project, e.g. with npm: ```bash npm add -D @quatico/websmith-testing ``` -## Usage: Test addon with an existing test project +We don't add jest as a dependency, so you need to install it yourself! + +### 1.1 Test your addon with virtual project files Compile a project with from an existing folder in `test-data/projects` with a addon from the `addons` folder in your filesystem. @@ -22,75 +37,161 @@ a addon from the `addons` folder in your filesystem. ```typescript // foobar-addon.test.ts import { compilationEnv } from '@quatico/websmith-testing'; +import { join } from 'path'; describe('FoobarAddon', () => { - it('should compile', () => { - const results = compilationEnv('/target') - .addAddons(['foobar-addon'], "../addons") - .addProject("simple-example", "../test-data/projects") - .compile(); - - expect(fileContent("simple.js")).toMatchInlineSnapshot(` - "import { foo } from 'foobar-addon'; - foo(); - " - `); - }); + it('should compile source files', () => { + const results = compilationEnv('./__TEST__') + .addAddon("my-addon", join(__dirname, "../addons")) + .addProjectFromSource({ + "bar.ts": `console.log("Hello, Bar!");`, + "foo.ts": `export class Foo { + constructor(public value: T) { + console.log("Hello, Foo!", JSON.stringify(value)); + } + }`, + }) + .compile(); + + expect(testObj.getCompiledFiles().getPaths()).toEqual([ + "/__TEST__/dist/bar.js", + "/__TEST__/dist/foo.js" + "/__TEST__/dist/my-addon-output.json" + ]); + expect(results.getCompiledFile("foo.js").getContent()).toMatchInlineSnapshot(` + "export class Foo { + value; + constructor(value) { + this.value = value; + console.log("Hello, Foo!", JSON.stringify(value)); + } + } + " + `); + }); }); ``` -Please note that the whole compilation is done in memory and no files are written to disk. If you want to write the compiled files to disk, you can use the options `virtual: false`: +The whole compilation is done in memory and no files are written to disk. If you want to write the compiled files to disk, you can add the option `virtual: false` to the compilation environment: ```typescript // foobar-addon.test.ts import { compilationEnv, type CompilationEnv } from '@quatico/websmith-testing'; +import { join } from 'path'; let compilation: CompilationEnv; afterEach(() => { - // Remove the compilation results from your disk - compilation.cleanup(); + // Remove all compilation results from your disk + compilation.cleanUp(); }); describe('FoobarAddon', () => { - it('should compile', () => { - const compilation = compilationEnv('/target', { virtual: false }); - - // Use the example from above - // Add addon and project to the compilation environment - }); + it('should compile', () => { + compilation = compilationEnv("./__TEST__", { virtual: false }) + .addAddon("my-addon", join(__dirname, "../addons")) + .addProjectFromSource({ /* your project code here */ }) + .compile(); + + // expect compiled results from disk with same API as before + }); }); ``` -## Usage: Test addon with virtual file content from your test +## 2 Usage in a more complex project -You can define the project files to be used to test your addon directly within your test: +You can setup your addon once and reuse it in multiple tests. The addon is compiled only once and can be used in multiple projects. ```typescript -// foobar-addon.test.ts -import { compilationEnv } from '@quatico/websmith-testing'; +// my-addon.test.ts +import { compilationEnv, type CompilationEnv } from '@quatico/websmith-testing'; +import { join } from 'path'; -describe('FoobarAddon', () => { - it('should compile', () => { - const results = compilationEnv('/target').addProjectFromSource({ - "./foo-bar/index.ts": `export * from "./target";`, - "./foo-bar/target.ts": `export class Target {}`, - }) - .addAddons(['foobar-addon'], join(__dirname, "../addons")) - .compile(); - - const actual = results.getCompiledFiles(); - - expect(actual.getContents()).toEquals([ - "export * from './target';", - "export class Target {}" - ]); - - expect(results.getCompiledFile("target.js").getContent()).toMatchInlineSnapshot(` - "export class Target {} - " - `); - }); +let compilation: CompilationEnv; + +beforeAll(() => { + compilation = compilationEnv("./__TEST__", { virtual: false }) + .addAddon("my-addon", join(__dirname, "../addons")); +}); + +afterEach(() => { + // Remove all compilation results from your disk + compilation.cleanUp("project"); +}); + +afterAll(() => { + // Remove all compilation results from your disk + compilation.cleanUp(); +}); + +describe('MyAddon', () => { + it('should compile project with simple component', () => { + compilation.addProjectFromSource({ /* your project code here */ }) + .compile(); + + // expect compiled results from disk with same API as before + }); + + it('should compile project with styled component', () => { + compilation.addProjectFromSource({ /* your project code here */ }) + .compile(); + + // expect compiled results from disk with same API as before + }); }); ``` + +## 3 Library API + +The library provides a simple API to compile projects and addons, navigate the project and compiled files, and compare compiled file contents with expected from the filesystem, or virtual snapshots. + +### 3.1 Compiler Addons + +#### `addAddon(addonName: string, addonSource?: string | Record): CompilationEnv` + +Add an addon to the compilation environment. The addon is compiled before the project and can be used in the project. The `addonSource` can be a path to a folder or a set of source files. The addon is compiled every time it is added to the environment. + +#### `addAddons(addonNames: string[], addonsSourceDir?: string): CompilationEnv` + +Add multiple addons to the compilation environment from a file path on disk. The addons are compiled before the project and can be used in the project. + +#### `getActiveAddons(): CompilerAddons` + +Get the active addons in the compilation environment. The addons are stored in memory or on disk and can be accessed with the `CompilerAddons` object. + +### 3.2 Project Files + +#### `addProjectFromSource(source: Record): CompilationEnv` + +Add a project to the compilation environment from a set of files. The project is compiled in the order the files are added to the project. Paths can be absolute or relative to the compilation root. + +#### `addProjectFromDisk(projectName: string, projectsSourceDir?: string): CompilationEnv` + +Add a project to the compilation environment from a folder on disk. The project files are copied to the compilation environments build directory. Paths can be absolute or relative to the compilation root. The `projectsSourceDir` is the path to the project's source folder in the virtual or actual file system. + +#### `addProjectFile(relativePath: string, content: string): CompilationEnv` + +Add a single file to the project. The file is copied to the compilation environment's build directory. + +#### `getProjectFiles(): ProjectFiles` + +Get the project files in the compilation environment. The project files are stored in memory or on disk and can be accessed with the `ProjectFiles` object. + +### 3.3 Compilation Results + +#### `compile(): CompilationResults` + +Compile the project and addons. The compiled files are stored in memory and can be accessed with the `CompilationResults` object. + +#### `getCompiledFiles(): CompiledFiles` + +Get the compiled files from the project and addons. The compiled files are stored in memory and can be accessed with the `CompiledFiles` object. + +#### `getCompiledFile(path: string): CompiledFile` + +Get a compiled file by its path. The compiled file is stored in memory and can be accessed with the `CompiledFile` object. + +#### `cleanUp(options: "project" | "addons" | "all" = "all"): CompilationEnv` + +Remove all compiled files from memory. Use `options` parameter to remove only project or addon files. This method can be called after each test to clean created files. From 240de58e624d6a151ec04f7b3b5f1e6168646a3b Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Tue, 7 May 2024 13:09:41 +0200 Subject: [PATCH 51/52] B Fixes flaky removal of working directory --- packages/testing/src/compilation/environment.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index 0c717b4f..e2016134 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -15,7 +15,6 @@ import { type CompilerAddon, type CompilerOptions, } from "@quatico/websmith-core"; -import { rmSync } from "fs"; import { Module } from "module"; import { basename, dirname, extname, isAbsolute, join } from "path"; import requireFromString from "require-from-string"; @@ -112,7 +111,7 @@ export class CompilationEnv { if (this.isVirtual()) { this.system.readDirectory(target).forEach(it => this.system.deleteFile!(it)); } else { - rmSync(target, { recursive: true }); + ts.sys.readDirectory(target).forEach(it => this.system.deleteFile!(it)); } } return this; From 4d7da059c49dc028f5312c31fb6262688a8c1547 Mon Sep 17 00:00:00 2001 From: Jan Wloka Date: Tue, 7 May 2024 14:59:53 +0200 Subject: [PATCH 52/52] B Fixes flaky removal of working directory (again) --- .../tests/foobar-replace-processor.test.ts | 2 +- .../tests/foobar-replace-transformer.test.ts | 6 +--- .../testing/src/compilation/environment.ts | 33 +++++++++++++------ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/examples/tests/foobar-replace-processor.test.ts b/packages/examples/tests/foobar-replace-processor.test.ts index 36594cda..30448d1d 100644 --- a/packages/examples/tests/foobar-replace-processor.test.ts +++ b/packages/examples/tests/foobar-replace-processor.test.ts @@ -22,7 +22,7 @@ describe("foobar-replace-processor", () => { testObj .addProjectFromSource({ "bar.ts": `console.log("Hello, Bar!");`, - "foo.ts": `export class Foobar {}`, + "foo.ts": `export class FooBar {}`, }) .compile(); diff --git a/packages/examples/tests/foobar-replace-transformer.test.ts b/packages/examples/tests/foobar-replace-transformer.test.ts index 88519c09..9435b7b7 100644 --- a/packages/examples/tests/foobar-replace-transformer.test.ts +++ b/packages/examples/tests/foobar-replace-transformer.test.ts @@ -4,7 +4,7 @@ import { join } from "path"; describe("foobar-replace-transformer", () => { let testObj: CompilationEnv; beforeAll(() => { - testObj = compilationEnv("./__TEST__", { compilerOptions: { project: { outDir: "dist" } }, virtual: false }).addAddon( + testObj = compilationEnv("./__TEST__", { compilerOptions: { project: { outDir: "dist" } } }).addAddon( "foobar-replace-transformer", join(__dirname, "../addons") ); @@ -14,10 +14,6 @@ describe("foobar-replace-transformer", () => { testObj.cleanUp("project"); }); - afterAll(() => { - testObj.cleanUp(); - }); - it("should replace 'foo' with 'bar' in the output files", () => { testObj .addProjectFromSource({ diff --git a/packages/testing/src/compilation/environment.ts b/packages/testing/src/compilation/environment.ts index e2016134..a92a8e03 100644 --- a/packages/testing/src/compilation/environment.ts +++ b/packages/testing/src/compilation/environment.ts @@ -22,6 +22,7 @@ import ts from "typescript"; import { compileOptions } from "../compile-options"; import { copyDirectory } from "./copy-directory"; import { resolvePath } from "./resolve-path"; +import { rmSync } from "fs"; const DEFAULT_ROOT_DIR = "/"; const DEFAULT_BUILD_DIR = "./src"; @@ -35,7 +36,7 @@ export class CompilationEnv { private buildDir: string; private system: ts.System; private virtual: boolean; - private addons?: AddonRegistry; + private addons: AddonRegistry; constructor(rootDir?: string, options?: Partial, addonConfig?: Partial) { const { virtual = true, compilerOptions = {}, useCaseSensitiveFileNames } = options ?? {}; @@ -73,10 +74,10 @@ export class CompilationEnv { }); const registryConfig = { - ...(addonConfig ?? {}), addonsDir: join(this.rootDir, "./addons"), reporter: new DefaultReporter(this.system), system: this.system, + ...(addonConfig ?? {}), }; this.addons = new AddonRegistry(registryConfig); if (!this.system.directoryExists(this.addons.getAddonsDir())) { @@ -93,6 +94,10 @@ export class CompilationEnv { return this.rootDir; } + public getOutDir(): string { + return resolvePath(this.system, this.rootDir, this.compilerOptions.project.outDir ?? DEFAULT_OUT_DIR); + } + public getCompilerOptions(): CompilerOptions { return this.compilerOptions; } @@ -106,14 +111,22 @@ export class CompilationEnv { } public cleanUp(options: "project" | "addons" | "all" = "all"): this { - const target = options === "project" ? this.getProjectDir() : options === "addons" && this.addons ? this.addons.getAddonsDir() : this.rootDir; - if (this.system.directoryExists(target)) { - if (this.isVirtual()) { - this.system.readDirectory(target).forEach(it => this.system.deleteFile!(it)); - } else { - ts.sys.readDirectory(target).forEach(it => this.system.deleteFile!(it)); - } + let directories = []; + switch (options) { + case "all": + directories = [this.rootDir]; + break; + case "project": + directories = [this.buildDir, this.getOutDir()]; + break; + case "addons": + directories = [this.addons.getAddonsDir()]; + break; } + directories.forEach(dir => + this.virtual ? this.system.readDirectory(dir).forEach((it: string) => this.system.deleteFile!(it)) : rmSync(dir, { recursive: true }) + ); + return this; } @@ -290,7 +303,7 @@ export class CompilationEnv { acc[filePath] = content; } else { if (filePath.includes(addonName)) { - acc[join(this.addons!.getAddonsDir(), filePath)] = content; + acc[join(this.addons.getAddonsDir(), filePath)] = content; } else { acc[join(addonTargetPath, filePath)] = content; }