From 61a4ffab7fc8c0bfebb90b070cf324d1577bb9e1 Mon Sep 17 00:00:00 2001 From: Julien Polo Date: Thu, 26 Mar 2026 23:46:15 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20configurator=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- configurator.config.ts | 5 + configurator.preset.ts | 6 + package.json | 2 + packages/configurator-core/package.json | 4 +- packages/configurator-core/src/context.ts | 4 + .../configurator-core/src/directory.spec.ts | 45 ++ packages/configurator-core/src/directory.ts | 15 +- packages/configurator-core/src/file.spec.ts | 64 ++ packages/configurator-core/src/file.ts | 19 +- packages/configurator-core/src/index.spec.ts | 2 + packages/configurator-core/src/index.ts | 1 + packages/configurator-core/src/json.spec.ts | 25 +- packages/configurator/CHANGELOG.md | 10 + packages/configurator/README.md | 44 ++ packages/configurator/package.json | 88 +++ .../configurator/src/application/index.ts | 2 + .../src/application/resolveConfig.spec.ts | 47 ++ .../src/application/resolveConfig.ts | 23 + .../src/application/runPreset.spec.ts | 74 ++ .../configurator/src/application/runPreset.ts | 16 + packages/configurator/src/cli.ts | 4 + packages/configurator/src/cli/BaseCommand.ts | 18 + packages/configurator/src/cli/RootCommand.ts | 15 + packages/configurator/src/cli/RunCommand.ts | 29 + packages/configurator/src/cli/runCLI.ts | 25 + packages/configurator/src/config.spec.ts | 14 + packages/configurator/src/config.ts | 2 + .../configurator/src/config/ResolvedConfig.ts | 5 + .../configurator/src/config/UserConfig.ts | 22 + .../configurator/src/config/defineConfig.ts | 4 + packages/configurator/src/index.spec.ts | 16 + packages/configurator/src/index.ts | 3 + .../src/infrastructure/ConfigLoader.spec.ts | 25 + .../src/infrastructure/ConfigLoader.ts | 30 + .../src/infrastructure/EnvLoader.spec.ts | 82 +++ .../src/infrastructure/EnvLoader.ts | 11 + .../src/infrastructure/EnvSchema.ts | 46 ++ .../src/infrastructure/PresetLoader.ts | 52 ++ packages/configurator/src/meta.ts | 12 + packages/configurator/src/runtime.spec.ts | 16 + packages/configurator/src/runtime.ts | 3 + packages/configurator/src/runtime/Preset.ts | 7 + .../src/runtime/RuntimeContext.ts | 58 ++ .../configurator/src/runtime/definePreset.ts | 17 + .../src/runtime/useRuntimeContext.ts | 7 + packages/configurator/tsconfig.build.json | 10 + packages/configurator/tsconfig.json | 8 + packages/configurator/tsdown.config.ts | 6 + packages/configurator/vitest.config.mts | 16 + pnpm-lock.yaml | 693 ++++++++++++++++++ 50 files changed, 1738 insertions(+), 14 deletions(-) create mode 100644 configurator.config.ts create mode 100644 configurator.preset.ts create mode 100644 packages/configurator-core/src/context.ts create mode 100644 packages/configurator/CHANGELOG.md create mode 100644 packages/configurator/README.md create mode 100644 packages/configurator/package.json create mode 100644 packages/configurator/src/application/index.ts create mode 100644 packages/configurator/src/application/resolveConfig.spec.ts create mode 100644 packages/configurator/src/application/resolveConfig.ts create mode 100644 packages/configurator/src/application/runPreset.spec.ts create mode 100644 packages/configurator/src/application/runPreset.ts create mode 100644 packages/configurator/src/cli.ts create mode 100644 packages/configurator/src/cli/BaseCommand.ts create mode 100644 packages/configurator/src/cli/RootCommand.ts create mode 100644 packages/configurator/src/cli/RunCommand.ts create mode 100644 packages/configurator/src/cli/runCLI.ts create mode 100644 packages/configurator/src/config.spec.ts create mode 100644 packages/configurator/src/config.ts create mode 100644 packages/configurator/src/config/ResolvedConfig.ts create mode 100644 packages/configurator/src/config/UserConfig.ts create mode 100644 packages/configurator/src/config/defineConfig.ts create mode 100644 packages/configurator/src/index.spec.ts create mode 100644 packages/configurator/src/index.ts create mode 100644 packages/configurator/src/infrastructure/ConfigLoader.spec.ts create mode 100644 packages/configurator/src/infrastructure/ConfigLoader.ts create mode 100644 packages/configurator/src/infrastructure/EnvLoader.spec.ts create mode 100644 packages/configurator/src/infrastructure/EnvLoader.ts create mode 100644 packages/configurator/src/infrastructure/EnvSchema.ts create mode 100644 packages/configurator/src/infrastructure/PresetLoader.ts create mode 100644 packages/configurator/src/meta.ts create mode 100644 packages/configurator/src/runtime.spec.ts create mode 100644 packages/configurator/src/runtime.ts create mode 100644 packages/configurator/src/runtime/Preset.ts create mode 100644 packages/configurator/src/runtime/RuntimeContext.ts create mode 100644 packages/configurator/src/runtime/definePreset.ts create mode 100644 packages/configurator/src/runtime/useRuntimeContext.ts create mode 100644 packages/configurator/tsconfig.build.json create mode 100644 packages/configurator/tsconfig.json create mode 100644 packages/configurator/tsdown.config.ts create mode 100644 packages/configurator/vitest.config.mts diff --git a/configurator.config.ts b/configurator.config.ts new file mode 100644 index 000000000..2649d2f46 --- /dev/null +++ b/configurator.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from '@w5s/configurator/config'; + +export default defineConfig({ + preset: './configurator.preset.ts', +}); diff --git a/configurator.preset.ts b/configurator.preset.ts new file mode 100644 index 000000000..a6fcd7ad4 --- /dev/null +++ b/configurator.preset.ts @@ -0,0 +1,6 @@ +import { definePreset, useRuntimeContext } from '@w5s/configurator-core'; + +export default definePreset((config) => { + console.log(config); + console.log(useRuntimeContext()); +}); diff --git a/package.json b/package.json index d6c05ec03..df939c1da 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,8 @@ "@lerna-lite/publish": "5.0.0", "@types/node": "20.19.39", "@w5s/commitlint-config": "workspace:*", + "@w5s/configurator": "workspace:*", + "@w5s/configurator-core": "workspace:*", "@w5s/conventional-changelog": "workspace:*", "@w5s/cspell-config": "workspace:*", "@w5s/eslint-config": "workspace:*", diff --git a/packages/configurator-core/package.json b/packages/configurator-core/package.json index bb0b03fee..f94cc3ab8 100644 --- a/packages/configurator-core/package.json +++ b/packages/configurator-core/package.json @@ -60,7 +60,9 @@ "test": "pnpm run \"/^test:.*/\"", "test:src": "vitest run" }, - "dependencies": {}, + "dependencies": { + "@w5s/configurator": "workspace:*" + }, "devDependencies": { "@w5s/tsdown-config": "workspace:*", "tsdown": "0.21.7", diff --git a/packages/configurator-core/src/context.ts b/packages/configurator-core/src/context.ts new file mode 100644 index 000000000..ccfefbd42 --- /dev/null +++ b/packages/configurator-core/src/context.ts @@ -0,0 +1,4 @@ +export { + definePreset, + useRuntimeContext, +} from '@w5s/configurator/runtime'; diff --git a/packages/configurator-core/src/directory.spec.ts b/packages/configurator-core/src/directory.spec.ts index db9596053..f0279a7f6 100644 --- a/packages/configurator-core/src/directory.spec.ts +++ b/packages/configurator-core/src/directory.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import nodePath from 'node:path'; import { existsSync } from 'node:fs'; +import { RuntimeContext } from '@w5s/configurator/runtime'; import { directory, directorySync } from './directory.js'; import { getTestPath } from './testing/index.js'; @@ -28,4 +29,48 @@ describe.each([ }); }).not.toThrow(); }); + + it('should skip create in dryRun mode', async () => { + const path = nodePath.join(testPath, `${String(_)}-dry-run-create`); + + await RuntimeContext.run( + { + ...RuntimeContext.default, + isDebug: false, + isDryRun: true, + }, + async () => { + await subject({ + path, + state: 'present', + }); + }, + ); + + expect(existsSync(path)).toEqual(false); + }); + + it('should skip delete in dryRun mode', async () => { + const path = nodePath.join(testPath, `${String(_)}-dry-run-delete`); + directorySync({ + path, + state: 'present', + }); + + await RuntimeContext.run( + { + ...RuntimeContext.default, + isDebug: false, + isDryRun: true, + }, + async () => { + await subject({ + path, + state: 'absent', + }); + }, + ); + + expect(existsSync(path)).toEqual(true); + }); }); diff --git a/packages/configurator-core/src/directory.ts b/packages/configurator-core/src/directory.ts index 53f875bdd..8986f8de6 100644 --- a/packages/configurator-core/src/directory.ts +++ b/packages/configurator-core/src/directory.ts @@ -1,5 +1,6 @@ import { chmodSync, mkdirSync, rmSync } from 'node:fs'; import { chmod, mkdir, rm } from 'node:fs/promises'; +import { useRuntimeContext } from './context.js'; import { __exists } from './__exists.js'; import type { FileMode } from './FileMode.js'; import { __toMode } from './__toMode.js'; @@ -43,15 +44,16 @@ export interface DirectoryOptions { export async function directory(options: DirectoryOptions): Promise { const { path, state, mode } = options; const isPresent = await __exists(path); + const { isDryRun } = useRuntimeContext(); if (state === 'present') { const newMode = __toMode(mode); - if (!isPresent) { + if (!isDryRun && !isPresent) { await mkdir(path, { recursive: true, mode: newMode }); } - if (newMode != null && isPresent) { + if (!isDryRun && newMode != null && isPresent) { await chmod(path, newMode); } - } else if (isPresent) { + } else if (!isDryRun && isPresent) { await rm(path, { recursive: true }); } } @@ -77,15 +79,16 @@ export async function directory(options: DirectoryOptions): Promise { export function directorySync(options: DirectoryOptions): void { const { path, state, mode } = options; const isPresent = __existsSync(path); + const { isDryRun } = useRuntimeContext(); if (state === 'present') { const newMode = __toMode(mode); - if (!isPresent) { + if (!isDryRun && !isPresent) { mkdirSync(path, { recursive: true, mode: newMode }); } - if (newMode != null && isPresent) { + if (!isDryRun && newMode != null && isPresent) { chmodSync(path, newMode); } - } else if (isPresent) { + } else if (!isDryRun && isPresent) { rmSync(path, { recursive: true }); } } diff --git a/packages/configurator-core/src/file.spec.ts b/packages/configurator-core/src/file.spec.ts index 8e0d3b93c..fc429bda3 100644 --- a/packages/configurator-core/src/file.spec.ts +++ b/packages/configurator-core/src/file.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { chmod, readFile, stat, writeFile } from 'node:fs/promises'; import nodePath from 'node:path'; +import { RuntimeContext } from '@w5s/configurator/runtime'; import { file, fileSync } from './file.js'; import { getTestPath } from './testing/index.js'; @@ -133,4 +134,67 @@ describe(file, () => { await expect(readFile(path, 'utf8')).resolves.toEqual('foo'); await expect(readMode(path)).resolves.toEqual(0o640); }); + + it('should skip async mutations in dryRun mode', async () => { + const path = nodePath.join(testPath, 'dry-run-async'); + + await RuntimeContext.run( + { + ...RuntimeContext.default, + isDebug: false, + isDryRun: true, + }, + async () => { + await file({ + path, + state: 'present', + update: () => 'foo', + }); + }, + ); + + await expect(stat(path)).rejects.toThrow(); + }); + + it('should skip async deletes in dryRun mode', async () => { + const path = nodePath.join(testPath, 'dry-run-delete'); + await writeFile(path, 'foo'); + + await RuntimeContext.run( + { + ...RuntimeContext.default, + isDebug: false, + isDryRun: true, + }, + async () => { + await file({ + path, + state: 'absent', + }); + }, + ); + + await expect(readFile(path, 'utf8')).resolves.toEqual('foo'); + }); + + it('should skip sync mutations in dryRun mode', async () => { + const path = nodePath.join(testPath, 'dry-run-sync'); + + await RuntimeContext.run( + { + ...RuntimeContext.default, + isDebug: false, + isDryRun: true, + }, + async () => { + fileSync({ + path, + state: 'present', + update: () => 'foo', + }); + }, + ); + + await expect(stat(path)).rejects.toThrow(); + }); }); diff --git a/packages/configurator-core/src/file.ts b/packages/configurator-core/src/file.ts index c830d975e..647cd08d0 100644 --- a/packages/configurator-core/src/file.ts +++ b/packages/configurator-core/src/file.ts @@ -1,5 +1,6 @@ import { chmod, readFile, rm, writeFile } from 'node:fs/promises'; import { chmodSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { useRuntimeContext } from './context.js'; import { __exists } from './__exists.js'; import { __existsSync } from './__existsSync.js'; import type { FileMode } from './FileMode.js'; @@ -54,19 +55,22 @@ export interface FileOptions { */ export async function file(options: FileOptions): Promise { const { path, state, update, encoding = 'utf8', mode } = options; + const { isDryRun } = useRuntimeContext(); if (state === 'present') { const isPresent = await __exists(path); const previousContent = isPresent ? await readFile(path, encoding) : ''; const newContent = update == null ? (isPresent ? undefined : '') : update(previousContent); const newMode = __toMode(mode); - if (newContent != null) { + if (!isDryRun && newContent != null) { await writeFile(path, newContent, { encoding, mode: newMode }); } - if (newMode != null && (isPresent || newContent != null)) { + if (!isDryRun && newMode != null && (isPresent || newContent != null)) { await chmod(path, newMode); } } else { - await rm(path, { force: true }); + if (!isDryRun) { + await rm(path, { force: true }); + } } } @@ -91,18 +95,21 @@ export async function file(options: FileOptions): Promise { */ export function fileSync(options: FileOptions): void { const { path, state, update, encoding = 'utf8', mode } = options; + const { isDryRun } = useRuntimeContext(); if (state === 'present') { const isPresent = __existsSync(path); const previousContent = isPresent ? readFileSync(path, encoding) : ''; const newContent = update == null ? (isPresent ? undefined : '') : update(previousContent); const newMode = __toMode(mode); - if (newContent != null) { + if (!isDryRun && newContent != null) { writeFileSync(path, newContent, { encoding, mode: newMode }); } - if (newMode != null && (isPresent || newContent != null)) { + if (!isDryRun && newMode != null && (isPresent || newContent != null)) { chmodSync(path, newMode); } } else { - rmSync(path, { force: true }); + if (!isDryRun) { + rmSync(path, { force: true }); + } } } diff --git a/packages/configurator-core/src/index.spec.ts b/packages/configurator-core/src/index.spec.ts index 77bd53450..fb65c75f0 100644 --- a/packages/configurator-core/src/index.spec.ts +++ b/packages/configurator-core/src/index.spec.ts @@ -7,6 +7,7 @@ describe('index', () => { expect(Object.keys(Module).sort()).toEqual( [ // Public API + 'definePreset', 'directory', 'directorySync', 'block', @@ -16,6 +17,7 @@ describe('index', () => { 'json', 'jsonSync', 'meta', + 'useRuntimeContext', 'yarnConfig', 'yarnConfigSync', 'yarnVersion', diff --git a/packages/configurator-core/src/index.ts b/packages/configurator-core/src/index.ts index dc68fcd86..3367eddd8 100644 --- a/packages/configurator-core/src/index.ts +++ b/packages/configurator-core/src/index.ts @@ -5,3 +5,4 @@ export * from './json.js'; export * from './meta.js'; export * from './yarnConfig.js'; export * from './yarnVersion.js'; +export * from './context.js'; diff --git a/packages/configurator-core/src/json.spec.ts b/packages/configurator-core/src/json.spec.ts index abee2a90c..b145ee91f 100644 --- a/packages/configurator-core/src/json.spec.ts +++ b/packages/configurator-core/src/json.spec.ts @@ -1,6 +1,7 @@ import { describe, it, expect } from 'vitest'; -import { readFile } from 'node:fs/promises'; +import { readFile, writeFile } from 'node:fs/promises'; import nodePath from 'node:path'; +import { RuntimeContext } from '@w5s/configurator/runtime'; import { json } from './json.js'; import { getTestPath } from './testing/index.js'; @@ -30,4 +31,26 @@ describe(json, () => { }); await expect(readFile(path, 'utf8')).resolves.toEqual('["foo","bar"]'); }); + + it('should skip mutations in dryRun mode', async () => { + const path = nodePath.join(testPath, 'dry-run'); + await writeFile(path, '["foo"]'); + + await RuntimeContext.run( + { + ...RuntimeContext.default, + isDebug: false, + isDryRun: true, + }, + async () => { + await json({ + path, + state: 'present', + update: (content = []) => [...content, 'bar'], + }); + }, + ); + + await expect(readFile(path, 'utf8')).resolves.toEqual('["foo"]'); + }); }); diff --git a/packages/configurator/CHANGELOG.md b/packages/configurator/CHANGELOG.md new file mode 100644 index 000000000..653c98b9d --- /dev/null +++ b/packages/configurator/CHANGELOG.md @@ -0,0 +1,10 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## 1.0.0-alpha.0 (2026-03-26) + +### ✨ Features + +- Initialize @w5s/configurator package diff --git a/packages/configurator/README.md b/packages/configurator/README.md new file mode 100644 index 000000000..e5e8691e7 --- /dev/null +++ b/packages/configurator/README.md @@ -0,0 +1,44 @@ + +# W5S Configurator _(@w5s/configurator)_ + + +[![NPM Version][package-version-svg]][package-url] +[![License][license-image]][license-url] + + +> CLI tool to run configurator presets + + +## Installation + + +```console +npm install --save-dev @w5s/configurator +``` + + +## Usage + + +```json +"@w5s/configurator" +``` + + +## License + +[MIT][license-url] © Julien Polo + + + + + +[package-version-svg]: https://img.shields.io/npm/v/@w5s/configurator.svg?style=flat-square + + +[package-url]: https://www.npmjs.com/package/@w5s/configurator + + +[license-image]: https://img.shields.io/badge/license-MIT-green.svg?style=flat-square + +[license-url]: ../../LICENSE diff --git a/packages/configurator/package.json b/packages/configurator/package.json new file mode 100644 index 000000000..1ae975ade --- /dev/null +++ b/packages/configurator/package.json @@ -0,0 +1,88 @@ +{ + "name": "@w5s/configurator", + "version": "1.0.0-alpha.0", + "description": "CLI tool to run configurator presets", + "keywords": [ + "cli", + "config", + "configurator", + "preset" + ], + "homepage": "https://github.com/w5s/project-config/blob/main/packages/configurator#readme", + "bugs": { + "url": "https://github.com/w5s/project-config/issues" + }, + "repository": { + "type": "git", + "url": "git@github.com:w5s/project-config.git", + "directory": "packages/configurator" + }, + "license": "MIT", + "author": "Julien Polo ", + "type": "module", + "bin": { + "configurator": "dist/cli.js" + }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./config": { + "types": "./dist/config.d.ts", + "default": "./dist/config.js" + }, + "./runtime": { + "types": "./dist/runtime.d.ts", + "default": "./dist/runtime.js" + }, + "./dist/*": "./dist/*" + }, + "typings": "./index.d.ts", + "files": [ + "dist/", + "src/", + "index.js", + "index.d.ts", + "!*.d.ts.map", + "!**/*.spec.*", + "!**/__tests__/**" + ], + "scripts": { + "build": "pnpm run \"/^build:.*/\"", + "build:tsc": "tsdown", + "clean": "pnpm run \"/^clean:.*/\"", + "clean:tsc": "rm -rf dist", + "docs": "node ../../markdown.mjs", + "format": "pnpm run \"/^format:.*/\"", + "format:src": "eslint . --fix", + "lint": "pnpm run \"/^lint:.*/\"", + "lint:src": "eslint .", + "postpack": "clean-package restore", + "prepack": "clean-package", + "prepublishOnly": "pnpm run clean;pnpm run build", + "spellcheck": "cspell --no-progress '**'", + "test": "pnpm run \"/^test:.*/\"", + "test:src": "vitest run" + }, + "dependencies": { + "@t3-oss/env-core": "^0.11.1", + "c12": "^3.2.0", + "clipanion": "^4.0.0-rc.4", + "zod": "^3.24.4" + }, + "devDependencies": { + "@w5s/tsdown-config": "workspace:*", + "tsdown": "0.21.5", + "vite": "8.0.2", + "vitest": "4.1.1" + }, + "clean-package": "../../clean-package.config.cjs", + "engines": { + "node": ">=20.0.0" + }, + "publishConfig": { + "access": "public" + }, + "sideEffect": false +} diff --git a/packages/configurator/src/application/index.ts b/packages/configurator/src/application/index.ts new file mode 100644 index 000000000..c9885884b --- /dev/null +++ b/packages/configurator/src/application/index.ts @@ -0,0 +1,2 @@ +export { resolveConfig } from './resolveConfig.js'; +export { runPreset } from './runPreset.js'; diff --git a/packages/configurator/src/application/resolveConfig.spec.ts b/packages/configurator/src/application/resolveConfig.spec.ts new file mode 100644 index 000000000..b01a8e3be --- /dev/null +++ b/packages/configurator/src/application/resolveConfig.spec.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from 'vitest'; +import { resolveConfig } from './resolveConfig.js'; + +describe('resolveEffectiveConfig', () => { + it('prefers args over env and config', () => { + const resolved = resolveConfig( + { preset: 'from-args', dryRun: true }, + { preset: 'from-env', dryRun: false }, + { config: { preset: 'from-config', dryRun: false }, configFile: undefined }, + ); + + expect(resolved.config.preset).toBe('from-args'); + expect(resolved.config.dryRun).toBe(true); + }); + + it('prefers env over config', () => { + const resolved = resolveConfig( + {}, + { preset: 'from-env', dryRun: true }, + { config: { preset: 'from-config', dryRun: false }, configFile: undefined }, + ); + + expect(resolved.config.preset).toBe('from-env'); + expect(resolved.config.dryRun).toBe(true); + }); + + it('uses config when args and env are missing', () => { + const resolved = resolveConfig( + {}, + {}, + { config: { preset: 'from-config', dryRun: true }, configFile: undefined }, + ); + + expect(resolved.config.preset).toBe('from-config'); + expect(resolved.config.dryRun).toBe(true); + }); + + it('defaults dryRun to false when omitted everywhere', () => { + const resolved = resolveConfig( + {}, + {}, + { config: { preset: 'from-config' }, configFile: undefined }, + ); + + expect(resolved.config.dryRun).toBe(false); + }); +}); diff --git a/packages/configurator/src/application/resolveConfig.ts b/packages/configurator/src/application/resolveConfig.ts new file mode 100644 index 000000000..981107d72 --- /dev/null +++ b/packages/configurator/src/application/resolveConfig.ts @@ -0,0 +1,23 @@ +import type { ResolvedConfig } from '../config/ResolvedConfig.js'; +import type { UserConfig } from '../config/UserConfig.js'; +import type { ConfigLoaderResult } from '../infrastructure/ConfigLoader.js'; + +export interface ResolveConfigResult { + readonly config: ResolvedConfig; + readonly configFile: string | undefined; +} + +export function resolveConfig( + args: UserConfig, + env: UserConfig, + loaded: ConfigLoaderResult, +): ResolveConfigResult { + const preset = args.preset ?? env.preset ?? loaded.config.preset; + const debug = args.debug ?? env.debug ?? loaded.config.debug ?? false; + const dryRun = args.dryRun ?? env.dryRun ?? loaded.config.dryRun ?? false; + + return { + config: { preset, debug, dryRun }, + configFile: loaded.configFile ?? undefined, + }; +} diff --git a/packages/configurator/src/application/runPreset.spec.ts b/packages/configurator/src/application/runPreset.spec.ts new file mode 100644 index 000000000..b5e275159 --- /dev/null +++ b/packages/configurator/src/application/runPreset.spec.ts @@ -0,0 +1,74 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'; +import nodePath from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { runPreset } from './runPreset.js'; + +describe('runPreset', () => { + const TEST_PATH = '.temp/configurator-preset'; + + beforeEach(async () => { + await rm(TEST_PATH, { recursive: true, force: true }); + await mkdir(TEST_PATH, { recursive: true }); + }); + + it('executes the default export function', async () => { + const outputPath = nodePath.resolve(TEST_PATH, 'out.txt'); + const presetPath = nodePath.resolve(TEST_PATH, 'preset.mjs'); + const presetSource = `export default async (config) => { + const { writeFile } = await import('node:fs/promises'); + await writeFile(${JSON.stringify(outputPath)}, String(config.preset)); +};`; + + await writeFile(presetPath, presetSource); + + await runPreset({ + config: { preset: './preset.mjs', debug: false, dryRun: false }, + configFile: nodePath.join(TEST_PATH, 'configurator.config.json'), + }); + + await expect(readFile(outputPath, 'utf8')).resolves.toBe('./preset.mjs'); + }); + + it('throws when preset is missing', async () => { + await expect(runPreset({ + config: { preset: undefined, debug: false, dryRun: false }, + configFile: undefined, + })).rejects.toThrow(/preset/i); + }); + + it('throws when preset default export is not a function', async () => { + const presetPath = nodePath.resolve(TEST_PATH, 'invalid.mjs'); + await writeFile(presetPath, 'export default 42;'); + + await expect( + runPreset({ + config: { preset: './invalid.mjs', debug: false, dryRun: false }, + configFile: nodePath.join(TEST_PATH, 'configurator.config.json'), + }), + ).rejects.toThrow(/default function/i); + }); + + it('exposes dryRun through the runtime context', async () => { + const outputPath = nodePath.resolve(TEST_PATH, 'context.json'); + const presetPath = nodePath.resolve(TEST_PATH, 'context-preset.mjs'); + const runtimeModule = pathToFileURL(nodePath.resolve('src/runtime.ts')).href; + const presetSource = `export default async () => { + const { useRuntimeContext } = await import(${JSON.stringify(runtimeModule)}); + const { writeFile } = await import('node:fs/promises'); + const context = useRuntimeContext(); + await writeFile(${JSON.stringify(outputPath)}, JSON.stringify(context)); +};`; + + await writeFile(presetPath, presetSource); + + await runPreset({ + config: { preset: './context-preset.mjs', debug: true, dryRun: true }, + configFile: nodePath.join(TEST_PATH, 'configurator.config.json'), + }); + + await expect(readFile(outputPath, 'utf8')).resolves.toBe( + JSON.stringify({ isDebug: true, isDryRun: true }), + ); + }); +}); diff --git a/packages/configurator/src/application/runPreset.ts b/packages/configurator/src/application/runPreset.ts new file mode 100644 index 000000000..733cd19a9 --- /dev/null +++ b/packages/configurator/src/application/runPreset.ts @@ -0,0 +1,16 @@ +import type { ResolveConfigResult } from './resolveConfig.js'; +import { PresetLoader } from '../infrastructure/PresetLoader.js'; +import { RuntimeContext } from '../runtime/RuntimeContext.js'; + +export async function runPreset(resolved: ResolveConfigResult): Promise { + const preset = resolved.config.preset; + + if (preset == null || preset.length === 0) { + throw new Error('No preset configured. Use --preset, CONFIGURATOR_PRESET, or a configurator config file.'); + } + + const presetFn = await PresetLoader.load(preset, { configFile: resolved.configFile, cwd: process.cwd() }); + + const context = RuntimeContext.create(resolved.config); + await RuntimeContext.run(context, () => presetFn(resolved.config)); +} diff --git a/packages/configurator/src/cli.ts b/packages/configurator/src/cli.ts new file mode 100644 index 000000000..5d8e01ff3 --- /dev/null +++ b/packages/configurator/src/cli.ts @@ -0,0 +1,4 @@ +#!/usr/bin/env node +import { runCLI } from './cli/runCLI.js'; + +runCLI(); diff --git a/packages/configurator/src/cli/BaseCommand.ts b/packages/configurator/src/cli/BaseCommand.ts new file mode 100644 index 000000000..46678bd0e --- /dev/null +++ b/packages/configurator/src/cli/BaseCommand.ts @@ -0,0 +1,18 @@ +import { Command, Option } from 'clipanion'; + +export abstract class BaseCommand extends Command { + readonly preset = Option.String('--preset,-p', { + description: 'Preset module/package to load.', + required: false, + }); + + readonly debug = Option.Boolean('--debug,-g', { + description: 'Debug mode.', + required: false, + }); + + readonly dryRun = Option.Boolean('--dry-run', { + description: 'Preview changes without mutating files.', + required: false, + }); +} diff --git a/packages/configurator/src/cli/RootCommand.ts b/packages/configurator/src/cli/RootCommand.ts new file mode 100644 index 000000000..3d4b1db53 --- /dev/null +++ b/packages/configurator/src/cli/RootCommand.ts @@ -0,0 +1,15 @@ +import { Command } from 'clipanion'; +import { BaseCommand } from './BaseCommand.js'; + +export class RootCommand extends BaseCommand { + static override paths = [Command.Default]; + static override usage = Command.Usage({ + description: 'Configurator CLI.', + details: 'Use the run subcommand to execute a preset.', + }); + + async execute(): Promise { + this.context.stdout.write(this.cli.usage(null, { detailed: true })); + return 0; + } +} diff --git a/packages/configurator/src/cli/RunCommand.ts b/packages/configurator/src/cli/RunCommand.ts new file mode 100644 index 000000000..27a8ecaae --- /dev/null +++ b/packages/configurator/src/cli/RunCommand.ts @@ -0,0 +1,29 @@ +import { Command } from 'clipanion'; +import { ConfigLoader } from '../infrastructure/ConfigLoader.js'; +import { EnvLoader } from '../infrastructure/EnvLoader.js'; +import { resolveConfig } from '../application/resolveConfig.js'; +import { runPreset } from '../application/runPreset.js'; +import { BaseCommand } from './BaseCommand.js'; + +export class RunCommand extends BaseCommand { + static override paths = [['run']]; + static override usage = Command.Usage({ + description: 'Run a configurator preset.', + details: 'Loads a configurator config, resolves the preset, and executes it.', + }); + + async execute(): Promise { + try { + const cwd = process.cwd(); + const loaded = await ConfigLoader.load({ cwd }); + const env = EnvLoader.load(process.env); + const resolved = resolveConfig({ preset: this.preset, debug: this.debug, dryRun: this.dryRun }, env, loaded); + + await runPreset(resolved); + return 0; + } catch (error) { + this.context.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); + return 1; + } + } +} diff --git a/packages/configurator/src/cli/runCLI.ts b/packages/configurator/src/cli/runCLI.ts new file mode 100644 index 000000000..a715cec2b --- /dev/null +++ b/packages/configurator/src/cli/runCLI.ts @@ -0,0 +1,25 @@ +import { Builtins, Cli } from 'clipanion'; +import { RootCommand } from './RootCommand.js'; +import { RunCommand } from './RunCommand.js'; +import { meta } from '../meta.js'; + +export async function runCLI(): Promise { + const cli = new Cli({ + binaryLabel: 'W5S Configurator', + binaryName: meta.binaryName, + binaryVersion: meta.binaryVersion, + }); + + cli.register(RootCommand); + cli.register(RunCommand); + cli.register(Builtins.HelpCommand); + cli.register(Builtins.VersionCommand); + return cli.runExit(process.argv.slice(2), { + stderr: process.stderr, + stdin: process.stdin, + stdout: process.stdout, + }).catch((error) => { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; + }); +}; diff --git a/packages/configurator/src/config.spec.ts b/packages/configurator/src/config.spec.ts new file mode 100644 index 000000000..93de47e1c --- /dev/null +++ b/packages/configurator/src/config.spec.ts @@ -0,0 +1,14 @@ +/* eslint-disable unicorn/no-array-sort */ +import { describe, it, expect } from 'vitest'; +import * as Module from './config.js'; + +describe('runtime', () => { + it('exports', () => { + expect(Object.keys(Module).sort()).toEqual( + [ + // Public API + 'defineConfig', + ].sort(), + ); + }); +}); diff --git a/packages/configurator/src/config.ts b/packages/configurator/src/config.ts new file mode 100644 index 000000000..c1e23a0fe --- /dev/null +++ b/packages/configurator/src/config.ts @@ -0,0 +1,2 @@ +export type * from './config/UserConfig.js'; +export * from './config/defineConfig.js'; diff --git a/packages/configurator/src/config/ResolvedConfig.ts b/packages/configurator/src/config/ResolvedConfig.ts new file mode 100644 index 000000000..0db498f4e --- /dev/null +++ b/packages/configurator/src/config/ResolvedConfig.ts @@ -0,0 +1,5 @@ +export interface ResolvedConfig { + readonly preset: string | undefined; + readonly debug: boolean; + readonly dryRun: boolean; +} diff --git a/packages/configurator/src/config/UserConfig.ts b/packages/configurator/src/config/UserConfig.ts new file mode 100644 index 000000000..58738f7e4 --- /dev/null +++ b/packages/configurator/src/config/UserConfig.ts @@ -0,0 +1,22 @@ +import type { InputConfig } from 'c12'; + +export interface UserConfig extends InputConfig<{ + /** + * The path to the preset file / module + * + * @example + * preset: './configurator.preset.ts' + * preset: '@my-org/my-preset' + */ + readonly preset?: string | undefined; + + /** + * Whether to enable debug mode. In debug mode, the configurator will print more detailed logs to the console. + */ + readonly debug?: boolean | undefined; + + /** + * Whether to enable dry-run mode. In dry-run mode, configurator-core filesystem helpers skip mutations. + */ + readonly dryRun?: boolean | undefined; +}> {} diff --git a/packages/configurator/src/config/defineConfig.ts b/packages/configurator/src/config/defineConfig.ts new file mode 100644 index 000000000..29baf7e5e --- /dev/null +++ b/packages/configurator/src/config/defineConfig.ts @@ -0,0 +1,4 @@ +import { createDefineConfig } from 'c12'; +import type { UserConfig } from './UserConfig.js'; + +export const defineConfig = createDefineConfig(); diff --git a/packages/configurator/src/index.spec.ts b/packages/configurator/src/index.spec.ts new file mode 100644 index 000000000..451e0d0e0 --- /dev/null +++ b/packages/configurator/src/index.spec.ts @@ -0,0 +1,16 @@ +/* eslint-disable unicorn/no-array-sort */ +import { describe, it, expect } from 'vitest'; +import * as Module from './index.js'; + +describe('index', () => { + it('exports', () => { + expect(Object.keys(Module).sort()).toEqual( + [ + // Public API + 'meta', + 'runCLI', + 'runPreset', + ].sort(), + ); + }); +}); diff --git a/packages/configurator/src/index.ts b/packages/configurator/src/index.ts new file mode 100644 index 000000000..b050a101e --- /dev/null +++ b/packages/configurator/src/index.ts @@ -0,0 +1,3 @@ +export { runPreset } from './application/index.js'; +export { runCLI } from './cli/runCLI.js'; +export * from './meta.js'; diff --git a/packages/configurator/src/infrastructure/ConfigLoader.spec.ts b/packages/configurator/src/infrastructure/ConfigLoader.spec.ts new file mode 100644 index 000000000..669068049 --- /dev/null +++ b/packages/configurator/src/infrastructure/ConfigLoader.spec.ts @@ -0,0 +1,25 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { mkdir, rm, writeFile } from 'node:fs/promises'; +import nodePath from 'node:path'; +import { ConfigLoader } from './ConfigLoader.js'; + +describe('ConfigLoader', () => { + const TEST_PATH = '.cache/configurator-config'; + + beforeEach(async () => { + await rm(TEST_PATH, { recursive: true, force: true }); + await mkdir(TEST_PATH, { recursive: true }); + }); + + describe(ConfigLoader.load, () => { + it('loads config from configurator.config.json', async () => { + const configPath = nodePath.join(TEST_PATH, 'configurator.config.json'); + await writeFile(configPath, JSON.stringify({ preset: 'from-file' }, null, 2)); + + const loaded = await ConfigLoader.load({ cwd: TEST_PATH }); + + expect(loaded.config.preset).toBe('from-file'); + expect(loaded.configFile).toContain('configurator.config.json'); + }); + }); +}); diff --git a/packages/configurator/src/infrastructure/ConfigLoader.ts b/packages/configurator/src/infrastructure/ConfigLoader.ts new file mode 100644 index 000000000..d5944f915 --- /dev/null +++ b/packages/configurator/src/infrastructure/ConfigLoader.ts @@ -0,0 +1,30 @@ +import { loadConfig } from 'c12'; +import type { UserConfig } from '../config/UserConfig.js'; +import { meta } from '../meta.js'; + +export interface ConfigLoaderResult { + readonly config: UserConfig; + readonly configFile: string | undefined; +} + +export interface ConfigLoaderOptions { + readonly cwd: string; +} + +/** + * @namespace + */ +export const ConfigLoader = { + async load(options: ConfigLoaderOptions): Promise { + const result = await loadConfig({ + name: meta.binaryName, + packageJson: [meta.binaryName], + cwd: options.cwd, + }); + + return { + config: result.config, + configFile: result.configFile ?? undefined, + }; + }, +}; diff --git a/packages/configurator/src/infrastructure/EnvLoader.spec.ts b/packages/configurator/src/infrastructure/EnvLoader.spec.ts new file mode 100644 index 000000000..4151deeb9 --- /dev/null +++ b/packages/configurator/src/infrastructure/EnvLoader.spec.ts @@ -0,0 +1,82 @@ +import { describe, expect, it } from 'vitest'; +import { EnvLoader } from './EnvLoader.js'; + +describe('EnvLoader', () => { + it('parses preset string and ignores empty string', () => { + const loaded = EnvLoader.load({ + CONFIGURATOR_PRESET: '', + }); + + expect(loaded.preset).toBeUndefined(); + + const loadedWithPreset = EnvLoader.load({ + CONFIGURATOR_PRESET: './configurator.preset.ts', + }); + + expect(loadedWithPreset.preset).toBe('./configurator.preset.ts'); + }); + + it('parses debug values', () => { + const truthyValues = ['true', '1', 'yes', 'TRUE', 'Yes']; + for (const value of truthyValues) { + const loaded = EnvLoader.load({ + CONFIGURATOR_DEBUG: value, + }); + + expect(loaded.debug).toBe(true); + } + + const falsyValues = ['false', '0', 'no', 'FALSE', 'No']; + for (const value of falsyValues) { + const loaded = EnvLoader.load({ + CONFIGURATOR_DEBUG: value, + }); + + expect(loaded.debug).toBe(false); + } + }); + + it('parses dryRun values', () => { + const truthyValues = ['true', '1', 'yes', 'TRUE', 'Yes']; + for (const value of truthyValues) { + const loaded = EnvLoader.load({ + CONFIGURATOR_DRY_RUN: value, + }); + + expect(loaded.dryRun).toBe(true); + } + + const falsyValues = ['false', '0', 'no', 'FALSE', 'No']; + for (const value of falsyValues) { + const loaded = EnvLoader.load({ + CONFIGURATOR_DRY_RUN: value, + }); + + expect(loaded.dryRun).toBe(false); + } + }); + + it('throws on invalid debug values', () => { + expect(() => + EnvLoader.load({ + CONFIGURATOR_DEBUG: 'maybe', + }), + ).toThrow('Invalid environment variables'); + }); + + it('throws on invalid dryRun values', () => { + expect(() => + EnvLoader.load({ + CONFIGURATOR_DRY_RUN: 'maybe', + }), + ).toThrow('Invalid environment variables'); + }); + + it('handles missing envs', () => { + const loaded = EnvLoader.load({}); + + expect(loaded.preset).toBeUndefined(); + expect(loaded.debug).toBeUndefined(); + expect(loaded.dryRun).toBeUndefined(); + }); +}); diff --git a/packages/configurator/src/infrastructure/EnvLoader.ts b/packages/configurator/src/infrastructure/EnvLoader.ts new file mode 100644 index 000000000..18085b6f8 --- /dev/null +++ b/packages/configurator/src/infrastructure/EnvLoader.ts @@ -0,0 +1,11 @@ +import type { UserConfig } from '../config/UserConfig.js'; +import { parseEnv } from './EnvSchema.js'; + +/** + * @namespace + */ +export const EnvLoader = { + load(env: NodeJS.ProcessEnv): UserConfig { + return parseEnv(env); + }, +}; diff --git a/packages/configurator/src/infrastructure/EnvSchema.ts b/packages/configurator/src/infrastructure/EnvSchema.ts new file mode 100644 index 000000000..40944e1c9 --- /dev/null +++ b/packages/configurator/src/infrastructure/EnvSchema.ts @@ -0,0 +1,46 @@ +import { createEnv } from '@t3-oss/env-core'; +import { z } from 'zod'; +import type { UserConfig } from '../config/UserConfig.js'; + +const booleanFromEnv = z.preprocess((value) => { + if (typeof value !== 'string') { + return value; + } + + const normalized = value.trim().toLowerCase(); + if (normalized.length === 0) { + return undefined; + } + + if (['true', '1', 'yes'].includes(normalized)) { + return true; + } + + if (['false', '0', 'no'].includes(normalized)) { + return false; + } + + return value; +}, z.boolean().optional()); + +export function parseEnv(env: NodeJS.ProcessEnv): UserConfig { + const validated = createEnv({ + server: { + CONFIGURATOR_PRESET: z.string().optional(), + CONFIGURATOR_DEBUG: booleanFromEnv, + CONFIGURATOR_DRY_RUN: booleanFromEnv, + }, + runtimeEnv: env, + emptyStringAsUndefined: true, + onValidationError: ({ issues }) => { + const errors = issues.map((issue) => issue.message).join('\n'); + throw new Error(`Invalid environment variables:\n${errors}`); + }, + }); + + return { + preset: validated.CONFIGURATOR_PRESET, + debug: validated.CONFIGURATOR_DEBUG, + dryRun: validated.CONFIGURATOR_DRY_RUN, + }; +} diff --git a/packages/configurator/src/infrastructure/PresetLoader.ts b/packages/configurator/src/infrastructure/PresetLoader.ts new file mode 100644 index 000000000..f38aeb32a --- /dev/null +++ b/packages/configurator/src/infrastructure/PresetLoader.ts @@ -0,0 +1,52 @@ +import { createRequire } from 'node:module'; +import nodePath from 'node:path'; +import { pathToFileURL } from 'node:url'; +import type { Preset, PresetModule } from '../runtime/Preset.js'; + +export interface PresetLoadOptions { + readonly configFile?: string | undefined; + readonly cwd: string; +} + +function isPathLike(value: string): boolean { + return value.startsWith('./') || value.startsWith('../') || nodePath.isAbsolute(value); +} + +/** + * @namespace + */ +export const PresetLoader = { + async load(preset: string, options: PresetLoadOptions): Promise { + const mod = await PresetLoader.loadModule(preset, options); + return PresetLoader.resolveFunction(mod); + }, + async loadModule(preset: string, options: PresetLoadOptions): Promise { + const baseDir = options.configFile + ? nodePath.resolve(options.cwd, nodePath.dirname(options.configFile)) + : options.cwd; + const requireFromBase = createRequire(nodePath.join(baseDir, 'configurator-resolve.cjs')); + + const resolvedPath = isPathLike(preset) + ? nodePath.resolve(baseDir, preset) + : requireFromBase.resolve(preset); + + const resolvedUrl = pathToFileURL(resolvedPath).href; + + try { + return (await import(resolvedUrl)) as PresetModule; + } catch { + const required = requireFromBase(resolvedPath) as PresetModule; + + return required; + } + }, + resolveFunction(module: PresetModule): Preset { + const candidate = (module as PresetModule).default ?? module; + + if (typeof candidate !== 'function') { + throw new TypeError('Preset module must export a default function.'); + } + + return candidate as Preset; + }, +}; diff --git a/packages/configurator/src/meta.ts b/packages/configurator/src/meta.ts new file mode 100644 index 000000000..e9d0076b6 --- /dev/null +++ b/packages/configurator/src/meta.ts @@ -0,0 +1,12 @@ +export const meta = Object.freeze({ + // @ts-ignore - these variables are injected at build time + name: (typeof __PACKAGE_NAME__ === 'undefined' ? '' : __PACKAGE_NAME__) as string, + // @ts-ignore - these variables are injected at build time + version: (typeof __PACKAGE_VERSION__ === 'undefined' ? '' : __PACKAGE_VERSION__) as string, + // @ts-ignore - these variables are injected at build time + buildNumber: 1 as number, // (typeof __PACKAGE_BUILD_NUMBER__ === 'undefined' ? 0 : __PACKAGE_BUILD_NUMBER__) as number, + binaryLabel: 'W5S Configurator', + binaryName: 'configurator', + // @ts-ignore - these variables are injected at build time + binaryVersion: (typeof __PACKAGE_VERSION__ === 'undefined' ? '' : __PACKAGE_VERSION__) as string, +}); diff --git a/packages/configurator/src/runtime.spec.ts b/packages/configurator/src/runtime.spec.ts new file mode 100644 index 000000000..08a2e5158 --- /dev/null +++ b/packages/configurator/src/runtime.spec.ts @@ -0,0 +1,16 @@ +/* eslint-disable unicorn/no-array-sort */ +import { describe, it, expect } from 'vitest'; +import * as Module from './runtime.js'; + +describe('runtime', () => { + it('exports', () => { + expect(Object.keys(Module).sort()).toEqual( + [ + // Public API + 'definePreset', + 'RuntimeContext', + 'useRuntimeContext', + ].sort(), + ); + }); +}); diff --git a/packages/configurator/src/runtime.ts b/packages/configurator/src/runtime.ts new file mode 100644 index 000000000..45a98eda0 --- /dev/null +++ b/packages/configurator/src/runtime.ts @@ -0,0 +1,3 @@ +export { definePreset } from './runtime/definePreset.js'; +export { useRuntimeContext } from './runtime/useRuntimeContext.js'; +export * from './runtime/RuntimeContext.js'; diff --git a/packages/configurator/src/runtime/Preset.ts b/packages/configurator/src/runtime/Preset.ts new file mode 100644 index 000000000..fc404e197 --- /dev/null +++ b/packages/configurator/src/runtime/Preset.ts @@ -0,0 +1,7 @@ +import type { UserConfig } from '../config/UserConfig.js'; + +export type Preset = (config: UserConfig) => void | Promise; + +export interface PresetModule { + readonly default?: unknown; +} diff --git a/packages/configurator/src/runtime/RuntimeContext.ts b/packages/configurator/src/runtime/RuntimeContext.ts new file mode 100644 index 000000000..64f242376 --- /dev/null +++ b/packages/configurator/src/runtime/RuntimeContext.ts @@ -0,0 +1,58 @@ +import { AsyncLocalStorage } from 'node:async_hooks'; +import type { ResolvedConfig } from '../config/ResolvedConfig.js'; + +export interface RuntimeContext { + /** + * Debug mode + */ + readonly isDebug: boolean; + + /** + * Dry-run mode (no actual changes will be made) + */ + readonly isDryRun: boolean; + + /** + * Log debug messages if debug mode is enabled + * + * @param args + */ + debug: (...args: unknown[]) => void; +} + +const storage = new AsyncLocalStorage(); + +/** + * @namespace + */ +export const RuntimeContext = { + storage, + create(config: ResolvedConfig): RuntimeContext { + const debug = + config.debug === true + ? (...args: unknown[]): void => { + // Keep the prefix short and consistent for filtering. + console.debug('[configurator]', ...args); + } + : () => {}; + + return { + isDebug: config.debug, + isDryRun: config.dryRun, + debug, + }; + }, + + default: Object.freeze({ + isDebug: false, + isDryRun: false, + debug: () => {}, + }) satisfies RuntimeContext, + + async run( + context: RuntimeContext, + fn: () => T | Promise, + ): Promise { + return await storage.run(context, fn); + }, +}; diff --git a/packages/configurator/src/runtime/definePreset.ts b/packages/configurator/src/runtime/definePreset.ts new file mode 100644 index 000000000..aafdc54cc --- /dev/null +++ b/packages/configurator/src/runtime/definePreset.ts @@ -0,0 +1,17 @@ +import type { Preset } from './Preset.js'; + +/** + * + * @example + * ```typescript + * import { definePreset } from '@w5s/configurator/runtime'; + * + * export default definePreset((config) => { + * + * }); + * ``` + * @param presetFn + */ +export function definePreset(presetFn: Preset): Preset { + return presetFn; +} diff --git a/packages/configurator/src/runtime/useRuntimeContext.ts b/packages/configurator/src/runtime/useRuntimeContext.ts new file mode 100644 index 000000000..2cb858033 --- /dev/null +++ b/packages/configurator/src/runtime/useRuntimeContext.ts @@ -0,0 +1,7 @@ +import { RuntimeContext } from './RuntimeContext.js'; + +export type { ResolvedConfig } from '../config/ResolvedConfig.js'; + +export function useRuntimeContext(): RuntimeContext { + return RuntimeContext.storage.getStore() ?? RuntimeContext.default; +} diff --git a/packages/configurator/tsconfig.build.json b/packages/configurator/tsconfig.build.json new file mode 100644 index 000000000..924f2d1f5 --- /dev/null +++ b/packages/configurator/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig.json", + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "rootDir": "./src" + }, + "include": ["src"], + "exclude": ["**/*.spec.*", "**/*.test.*", "**/__mocks__/**"] +} diff --git a/packages/configurator/tsconfig.json b/packages/configurator/tsconfig.json new file mode 100644 index 000000000..7eb166f5f --- /dev/null +++ b/packages/configurator/tsconfig.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig.json", + "extends": "../../tsconfig.settings.json", + "compilerOptions": { + "declarationMap": true + }, + "exclude": ["dist/"] +} diff --git a/packages/configurator/tsdown.config.ts b/packages/configurator/tsdown.config.ts new file mode 100644 index 000000000..5e15583ac --- /dev/null +++ b/packages/configurator/tsdown.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from '@w5s/tsdown-config'; + +export default defineConfig({ + entry: ['src/index.ts', 'src/cli.ts', 'src/config.ts', 'src/runtime.ts', '!src/**/*.test.*', '!src/**/*.spec.*', '!**/__mocks__/**'], + format: ['esm'], +}); diff --git a/packages/configurator/vitest.config.mts b/packages/configurator/vitest.config.mts new file mode 100644 index 000000000..c28128c69 --- /dev/null +++ b/packages/configurator/vitest.config.mts @@ -0,0 +1,16 @@ +import { configDefaults, defineConfig } from 'vitest/config'; +import nodePath from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const rootDir = fileURLToPath(new URL('.', import.meta.url)); + +export default defineConfig({ + resolve: { + alias: { + '@w5s/configurator/runtime': nodePath.resolve(rootDir, 'src/runtime.ts'), + }, + }, + test: { + exclude: [...configDefaults.exclude], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7818e9b59..9b6d79051 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,12 @@ importers: '@w5s/commitlint-config': specifier: workspace:* version: link:packages/commitlint-config + '@w5s/configurator': + specifier: workspace:* + version: link:packages/configurator + '@w5s/configurator-core': + specifier: workspace:* + version: link:packages/configurator-core '@w5s/conventional-changelog': specifier: workspace:* version: link:packages/conventional-changelog @@ -121,7 +127,39 @@ importers: specifier: 4.1.4 version: 4.1.4(@types/node@20.19.39)(vite@8.0.8(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3)) + packages/configurator: + dependencies: + '@t3-oss/env-core': + specifier: ^0.11.1 + version: 0.11.1(typescript@6.0.2)(zod@3.25.76) + c12: + specifier: ^3.2.0 + version: 3.3.3 + clipanion: + specifier: ^4.0.0-rc.4 + version: 4.0.0-rc.4(typanion@3.14.0) + zod: + specifier: ^3.24.4 + version: 3.25.76 + devDependencies: + '@w5s/tsdown-config': + specifier: workspace:* + version: link:../tsdown-config + tsdown: + specifier: 0.21.5 + version: 0.21.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(synckit@0.11.12)(typescript@6.0.2) + vite: + specifier: 8.0.2 + version: 8.0.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3) + vitest: + specifier: 4.1.1 + version: 4.1.1(@types/node@20.19.39)(vite@8.0.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3)) + packages/configurator-core: + dependencies: + '@w5s/configurator': + specifier: workspace:* + version: link:../configurator devDependencies: '@w5s/tsdown-config': specifier: workspace:* @@ -396,6 +434,10 @@ packages: resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} + '@babel/generator@8.0.0-rc.2': + resolution: {integrity: sha512-oCQ1IKPwkzCeJzAPb7Fv8rQ9k5+1sG8mf2uoHiMInPYvkRfrDJxbTIbH51U+jstlkghus0vAi3EBvkfvEsYNLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + '@babel/generator@8.0.0-rc.3': resolution: {integrity: sha512-em37/13/nR320G4jab/nIIHZgc2Wz2y/D39lxnTyxB4/D/omPQncl/lSdlnJY1OhQcRGugTSIF2l/69o31C9dA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -408,15 +450,28 @@ packages: resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@8.0.0-rc.2': + resolution: {integrity: sha512-xExUBkuXWJjVuIbO7z6q7/BA9bgfJDEhVL0ggrggLMbg0IzCUWGT1hZGE8qUH7Il7/RD/a6cZ3AAFrrlp1LF/A==} + engines: {node: ^20.19.0 || >=22.12.0} + '@babel/helper-validator-identifier@8.0.0-rc.3': resolution: {integrity: sha512-8AWCJ2VJJyDFlGBep5GpaaQ9AAaE/FjAcrqI7jyssYhtL7WGV0DOKpJsQqM037xDbpRLHXsY8TwU7zDma7coOw==} engines: {node: ^20.19.0 || >=22.12.0} + '@babel/parser@8.0.0-rc.2': + resolution: {integrity: sha512-29AhEtcq4x8Dp3T72qvUMZHx0OMXCj4Jy/TEReQa+KWLln524Cj1fWb3QFi0l/xSpptQBR6y9RNEXuxpFvwiUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + '@babel/parser@8.0.0-rc.3': resolution: {integrity: sha512-B20dvP3MfNc/XS5KKCHy/oyWl5IA6Cn9YjXRdDlCjNmUFrjvLXMNUfQq/QUy9fnG2gYkKKcrto2YaF9B32ToOQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + '@babel/types@8.0.0-rc.2': + resolution: {integrity: sha512-91gAaWRznDwSX4E2tZ1YjBuIfnQVOFDCQ2r0Toby0gu4XEbyF623kXLMA8d4ZbCu+fINcrudkmEcwSUHgDDkNw==} + engines: {node: ^20.19.0 || >=22.12.0} + '@babel/types@8.0.0-rc.3': resolution: {integrity: sha512-mOm5ZrYmphGfqVWoH5YYMTITb3cDXsFgmvFlvkvWDMsR9X8RFnt7a0Wb6yNIdoFsiMO9WjYLq+U/FMtqIYAF8Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1084,6 +1139,12 @@ packages: '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + '@rolldown/binding-android-arm64@1.0.0-rc.11': + resolution: {integrity: sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-android-arm64@1.0.0-rc.12': resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1096,6 +1157,12 @@ packages: cpu: [arm64] os: [android] + '@rolldown/binding-darwin-arm64@1.0.0-rc.11': + resolution: {integrity: sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1108,6 +1175,12 @@ packages: cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-x64@1.0.0-rc.11': + resolution: {integrity: sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.0.0-rc.12': resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1120,6 +1193,12 @@ packages: cpu: [x64] os: [darwin] + '@rolldown/binding-freebsd-x64@1.0.0-rc.11': + resolution: {integrity: sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1132,6 +1211,12 @@ packages: cpu: [x64] os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': + resolution: {integrity: sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1144,6 +1229,13 @@ packages: cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1158,6 +1250,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': + resolution: {integrity: sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1172,6 +1271,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1186,6 +1292,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1200,6 +1313,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1214,6 +1334,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': + resolution: {integrity: sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1228,6 +1355,12 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': + resolution: {integrity: sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1240,6 +1373,11 @@ packages: cpu: [arm64] os: [openharmony] + '@rolldown/binding-wasm32-wasi@1.0.0-rc.11': + resolution: {integrity: sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==} engines: {node: '>=14.0.0'} @@ -1250,6 +1388,12 @@ packages: engines: {node: '>=14.0.0'} cpu: [wasm32] + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': + resolution: {integrity: sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1262,6 +1406,12 @@ packages: cpu: [arm64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': + resolution: {integrity: sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1274,6 +1424,9 @@ packages: cpu: [x64] os: [win32] + '@rolldown/pluginutils@1.0.0-rc.11': + resolution: {integrity: sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==} + '@rolldown/pluginutils@1.0.0-rc.12': resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} @@ -1355,6 +1508,15 @@ packages: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} + '@t3-oss/env-core@0.11.1': + resolution: {integrity: sha512-MaxOwEoG1ntCFoKJsS7nqwgcxLW1SJw238AJwfJeaz3P/8GtkxXZsPPolsz1AdYvUTbe3XvqZ/VCdfjt+3zmKw==} + peerDependencies: + typescript: '>=5.0.0' + zod: ^3.0.0 + peerDependenciesMeta: + typescript: + optional: true + '@tufjs/canonical-json@2.0.0': resolution: {integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==} engines: {node: ^16.14.0 || >=18.0.0} @@ -1547,9 +1709,23 @@ packages: vitest: optional: true + '@vitest/expect@4.1.1': + resolution: {integrity: sha512-xAV0fqBTk44Rn6SjJReEQkHP3RrqbJo6JQ4zZ7/uVOiJZRarBtblzrOfFIZeYUrukp2YD6snZG6IBqhOoHTm+A==} + '@vitest/expect@4.1.4': resolution: {integrity: sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==} + '@vitest/mocker@4.1.1': + resolution: {integrity: sha512-h3BOylsfsCLPeceuCPAAJ+BvNwSENgJa4hXoXu4im0bs9Lyp4URc4JYK4pWLZ4pG/UQn7AT92K6IByi6rE6g3A==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/mocker@4.1.4': resolution: {integrity: sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==} peerDependencies: @@ -1561,18 +1737,33 @@ packages: vite: optional: true + '@vitest/pretty-format@4.1.1': + resolution: {integrity: sha512-GM+TEQN5WhOygr1lp7skeVjdLPqqWMHsfzXrcHAqZJi/lIVh63H0kaRCY8MDhNWikx19zBUK8ceaLB7X5AH9NQ==} + '@vitest/pretty-format@4.1.4': resolution: {integrity: sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==} + '@vitest/runner@4.1.1': + resolution: {integrity: sha512-f7+FPy75vN91QGWsITueq0gedwUZy1fLtHOCMeQpjs8jTekAHeKP80zfDEnhrleviLHzVSDXIWuCIOFn3D3f8A==} + '@vitest/runner@4.1.4': resolution: {integrity: sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==} + '@vitest/snapshot@4.1.1': + resolution: {integrity: sha512-kMVSgcegWV2FibXEx9p9WIKgje58lcTbXgnJixfcg15iK8nzCXhmalL0ZLtTWLW9PH1+1NEDShiFFedB3tEgWg==} + '@vitest/snapshot@4.1.4': resolution: {integrity: sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==} + '@vitest/spy@4.1.1': + resolution: {integrity: sha512-6Ti/KT5OVaiupdIZEuZN7l3CZcR0cxnxt70Z0//3CtwgObwA6jZhmVBA3yrXSVN3gmwjgd7oDNLlsXz526gpRA==} + '@vitest/spy@4.1.4': resolution: {integrity: sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==} + '@vitest/utils@4.1.1': + resolution: {integrity: sha512-cNxAlaB3sHoCdL6pj6yyUXv9Gry1NHNg0kFTXdvSIZXLHsqKH7chiWOkwJ5s5+d/oMwcoG9T0bKU38JZWKusrQ==} + '@vitest/utils@4.1.4': resolution: {integrity: sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==} @@ -1774,6 +1965,14 @@ packages: builtins@1.0.3: resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==} + c12@3.3.3: + resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==} + peerDependencies: + magicast: '*' + peerDependenciesMeta: + magicast: + optional: true + cac@7.0.0: resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} engines: {node: '>=20.19.0'} @@ -1872,6 +2071,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -1886,6 +2089,12 @@ packages: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + citty@0.2.1: + resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} + clean-package@2.2.0: resolution: {integrity: sha512-vLv8kRqvh4smPDpqAYFPLEijTppAd/cfCz4yBcUGoVl/JKu6ZWKhlo+G/cAmwlSa29RudfBeuyiNEzas8bTwEQ==} hasBin: true @@ -1918,6 +2127,11 @@ packages: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} + clipanion@4.0.0-rc.4: + resolution: {integrity: sha512-CXkMQxU6s9GklO/1f714dkKBMu1lopS1WFF0B8o4AxPykR1hpozxSiUZ5ZUeBjfPgCWqbcNOtZVFhB8Lkfp1+Q==} + peerDependencies: + typanion: '*' + cliui@5.0.0: resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==} @@ -2016,6 +2230,9 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + configstore@3.1.5: resolution: {integrity: sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==} engines: {node: '>=4'} @@ -2024,6 +2241,10 @@ packages: resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==} engines: {node: '>=8'} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + conventional-changelog-angular@8.3.1: resolution: {integrity: sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==} engines: {node: '>=18'} @@ -2238,6 +2459,9 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -2600,6 +2824,9 @@ packages: exponential-backoff@3.1.3: resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + ext@1.7.0: resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} @@ -2798,6 +3025,10 @@ packages: get-tsconfig@4.13.7: resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + git-config-path@1.0.1: resolution: {integrity: sha512-KcJ2dlrrP5DbBnYIZ2nlikALfRhKzNSX0stvv3ImJ+fvC4hXKoV+U+74SV0upg+jlQZbrtQzc0bu6/Zh+7aQbg==} engines: {node: '>=0.10.0'} @@ -3990,6 +4221,9 @@ packages: resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} engines: {node: '>= 0.4'} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -4067,6 +4301,11 @@ packages: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} + nypm@0.6.5: + resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==} + engines: {node: '>=18'} + hasBin: true + object-deep-merge@2.0.0: resolution: {integrity: sha512-3DC3UMpeffLTHiuXSy/UG4NOIYTLlY9u3V82+djSCLYClWobZiS4ivYzpIUWrRY/nfsJ8cWsKyG3QfyLePmhvg==} @@ -4302,6 +4541,9 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4321,6 +4563,9 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -4403,6 +4648,9 @@ packages: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -4422,6 +4670,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + readme-badger@0.3.0: resolution: {integrity: sha512-+sMOLSs1imZUISZ2Rhz7qqVd77QtpcAPbGeIraFdgJmijb04YtdlPjGNBvDChTNtLbeQ6JNGQy3pOgslWfaP3g==} @@ -4517,6 +4769,25 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rolldown-plugin-dts@0.22.5: + resolution: {integrity: sha512-M/HXfM4cboo+jONx9Z0X+CUf3B5tCi7ni+kR5fUW50Fp9AlZk0oVLesibGWgCXDKFp5lpgQ9yhKoImUFjl3VZw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@ts-macro/tsc': ^0.3.6 + '@typescript/native-preview': '>=7.0.0-dev.20250601.1' + rolldown: ^1.0.0-rc.3 + typescript: ^5.0.0 || ^6.0.0-beta + vue-tsc: ~3.2.0 + peerDependenciesMeta: + '@ts-macro/tsc': + optional: true + '@typescript/native-preview': + optional: true + typescript: + optional: true + vue-tsc: + optional: true + rolldown-plugin-dts@0.23.2: resolution: {integrity: sha512-PbSqLawLgZBGcOGT3yqWBGn4cX+wh2nt5FuBGdcMHyOhoukmjbhYAl8NT9sE4U38Cm9tqLOIQeOrvzeayM0DLQ==} engines: {node: '>=20.19.0'} @@ -4536,6 +4807,11 @@ packages: vue-tsc: optional: true + rolldown@1.0.0-rc.11: + resolution: {integrity: sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rolldown@1.0.0-rc.12: resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4926,6 +5202,34 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tsdown@0.21.5: + resolution: {integrity: sha512-TlgNhfPioAD6ECCUnZsxcUsXXuPPR4Rrxz3az741kL/M3oGIET4a9GajSNRNRx+jIva73TYUKQybrEPkDYN+fQ==} + engines: {node: '>=20.19.0'} + hasBin: true + peerDependencies: + '@arethetypeswrong/core': ^0.18.1 + '@tsdown/css': 0.21.5 + '@tsdown/exe': 0.21.5 + '@vitejs/devtools': '*' + publint: ^0.3.0 + typescript: ^5.0.0 || ^6.0.0 + unplugin-unused: ^0.5.0 + peerDependenciesMeta: + '@arethetypeswrong/core': + optional: true + '@tsdown/css': + optional: true + '@tsdown/exe': + optional: true + '@vitejs/devtools': + optional: true + publint: + optional: true + typescript: + optional: true + unplugin-unused: + optional: true + tsdown@0.21.7: resolution: {integrity: sha512-ukKIxKQzngkWvOYJAyptudclkm4VQqbjq+9HF5K5qDO8GJsYtMh8gIRwicbnZEnvFPr6mquFwYAVZ8JKt3rY2g==} engines: {node: '>=20.19.0'} @@ -4968,6 +5272,9 @@ packages: resolution: {integrity: sha512-JXNkRe6H6MjSlk5UQRTjyoKX5YN2zlc2632xcSlSFBao5yvbMWTpv9SNolOZlZmUlcDOHuszPLItbKrvcXnnZA==} hasBin: true + typanion@3.14.0: + resolution: {integrity: sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -5136,6 +5443,49 @@ packages: resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} engines: {node: ^20.17.0 || >=22.9.0} + vite@8.0.2: + resolution: {integrity: sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vite@8.0.8: resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5179,6 +5529,41 @@ packages: yaml: optional: true + vitest@4.1.1: + resolution: {integrity: sha512-yF+o4POL41rpAzj5KVILUxm1GCjKnELvaqmU9TLLUbMfDzuN0UpUR9uaDs+mCtjPe+uYPksXDRLQGGPvj1cTmA==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.1 + '@vitest/browser-preview': 4.1.1 + '@vitest/browser-webdriverio': 4.1.1 + '@vitest/ui': 4.1.1 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vitest@4.1.4: resolution: {integrity: sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -5416,6 +5801,9 @@ packages: zeptomatch@2.1.0: resolution: {integrity: sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -5432,6 +5820,15 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/generator@8.0.0-rc.2': + dependencies: + '@babel/parser': 8.0.0-rc.3 + '@babel/types': 8.0.0-rc.3 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@types/jsesc': 2.5.1 + jsesc: 3.1.0 + '@babel/generator@8.0.0-rc.3': dependencies: '@babel/parser': 8.0.0-rc.3 @@ -5445,12 +5842,23 @@ snapshots: '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@8.0.0-rc.2': {} + '@babel/helper-validator-identifier@8.0.0-rc.3': {} + '@babel/parser@8.0.0-rc.2': + dependencies: + '@babel/types': 8.0.0-rc.3 + '@babel/parser@8.0.0-rc.3': dependencies: '@babel/types': 8.0.0-rc.3 + '@babel/types@8.0.0-rc.2': + dependencies: + '@babel/helper-string-parser': 8.0.0-rc.3 + '@babel/helper-validator-identifier': 8.0.0-rc.3 + '@babel/types@8.0.0-rc.3': dependencies: '@babel/helper-string-parser': 8.0.0-rc.3 @@ -6313,78 +6721,122 @@ snapshots: dependencies: quansync: 1.0.0 + '@rolldown/binding-android-arm64@1.0.0-rc.11': + optional: true + '@rolldown/binding-android-arm64@1.0.0-rc.12': optional: true '@rolldown/binding-android-arm64@1.0.0-rc.15': optional: true + '@rolldown/binding-darwin-arm64@1.0.0-rc.11': + optional: true + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': optional: true '@rolldown/binding-darwin-arm64@1.0.0-rc.15': optional: true + '@rolldown/binding-darwin-x64@1.0.0-rc.11': + optional: true + '@rolldown/binding-darwin-x64@1.0.0-rc.12': optional: true '@rolldown/binding-darwin-x64@1.0.0-rc.15': optional: true + '@rolldown/binding-freebsd-x64@1.0.0-rc.11': + optional: true + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': optional: true '@rolldown/binding-freebsd-x64@1.0.0-rc.15': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': + optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': optional: true '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': optional: true + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': + optional: true + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': optional: true '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': optional: true + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': + optional: true + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': optional: true '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': optional: true + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': + optional: true + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': optional: true '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': optional: true + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': + optional: true + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': optional: true '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': optional: true + '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': + optional: true + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': optional: true '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': optional: true + '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': + optional: true + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': optional: true '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': optional: true + '@rolldown/binding-wasm32-wasi@1.0.0-rc.11(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': dependencies: '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) @@ -6400,18 +6852,26 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) optional: true + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': + optional: true + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': optional: true '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': optional: true + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': + optional: true + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': optional: true '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': optional: true + '@rolldown/pluginutils@1.0.0-rc.11': {} + '@rolldown/pluginutils@1.0.0-rc.12': {} '@rolldown/pluginutils@1.0.0-rc.15': {} @@ -6488,6 +6948,12 @@ snapshots: dependencies: defer-to-connect: 2.0.1 + '@t3-oss/env-core@0.11.1(typescript@6.0.2)(zod@3.25.76)': + dependencies: + zod: 3.25.76 + optionalDependencies: + typescript: 6.0.2 + '@tufjs/canonical-json@2.0.0': {} '@tufjs/models@4.1.0': @@ -6705,6 +7171,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/expect@4.1.1': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.1 + '@vitest/utils': 4.1.1 + chai: 6.2.2 + tinyrainbow: 3.1.0 + '@vitest/expect@4.1.4': dependencies: '@standard-schema/spec': 1.1.0 @@ -6714,6 +7189,14 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 + '@vitest/mocker@4.1.1(vite@8.0.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3))': + dependencies: + '@vitest/spy': 4.1.1 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3) + '@vitest/mocker@4.1.4(vite@8.0.8(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.4 @@ -6722,15 +7205,31 @@ snapshots: optionalDependencies: vite: 8.0.8(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3) + '@vitest/pretty-format@4.1.1': + dependencies: + tinyrainbow: 3.1.0 + '@vitest/pretty-format@4.1.4': dependencies: tinyrainbow: 3.1.0 + '@vitest/runner@4.1.1': + dependencies: + '@vitest/utils': 4.1.1 + pathe: 2.0.3 + '@vitest/runner@4.1.4': dependencies: '@vitest/utils': 4.1.4 pathe: 2.0.3 + '@vitest/snapshot@4.1.1': + dependencies: + '@vitest/pretty-format': 4.1.1 + '@vitest/utils': 4.1.1 + magic-string: 0.30.21 + pathe: 2.0.3 + '@vitest/snapshot@4.1.4': dependencies: '@vitest/pretty-format': 4.1.4 @@ -6738,8 +7237,16 @@ snapshots: magic-string: 0.30.21 pathe: 2.0.3 + '@vitest/spy@4.1.1': {} + '@vitest/spy@4.1.4': {} + '@vitest/utils@4.1.1': + dependencies: + '@vitest/pretty-format': 4.1.1 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + '@vitest/utils@4.1.4': dependencies: '@vitest/pretty-format': 4.1.4 @@ -6961,6 +7468,21 @@ snapshots: builtins@1.0.3: {} + c12@3.3.3: + dependencies: + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.6 + dotenv: 17.4.1 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 + rc9: 2.1.2 + cac@7.0.0: {} cacache@20.0.4: @@ -7079,6 +7601,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + chownr@3.0.0: {} ci-info@1.6.0: {} @@ -7087,6 +7613,12 @@ snapshots: ci-info@4.4.0: {} + citty@0.1.6: + dependencies: + consola: 3.4.2 + + citty@0.2.1: {} + clean-package@2.2.0: dependencies: dot-prop: 6.0.1 @@ -7112,6 +7644,10 @@ snapshots: cli-width@4.1.0: {} + clipanion@4.0.0-rc.4(typanion@3.14.0): + dependencies: + typanion: 3.14.0 + cliui@5.0.0: dependencies: string-width: 3.1.0 @@ -7217,6 +7753,8 @@ snapshots: concat-map@0.0.1: {} + confbox@0.2.4: {} + configstore@3.1.5: dependencies: dot-prop: 4.2.1 @@ -7235,6 +7773,8 @@ snapshots: write-file-atomic: 3.0.3 xdg-basedir: 4.0.0 + consola@3.4.2: {} + conventional-changelog-angular@8.3.1: dependencies: compare-func: 2.0.0 @@ -7492,6 +8032,8 @@ snapshots: dequal@2.0.3: {} + destr@2.0.5: {} + detect-indent@6.1.0: {} detect-indent@7.0.2: {} @@ -7990,6 +8532,8 @@ snapshots: exponential-backoff@3.1.3: {} + exsolve@1.0.8: {} + ext@1.7.0: dependencies: type: 2.7.3 @@ -8188,6 +8732,15 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + giget@2.0.0: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.6 + node-fetch-native: 1.6.7 + nypm: 0.6.5 + pathe: 2.0.3 + git-config-path@1.0.1: dependencies: extend-shallow: 2.0.1 @@ -9633,6 +10186,8 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 + node-fetch-native@1.6.7: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -9728,6 +10283,12 @@ snapshots: path-key: 4.0.0 unicorn-magic: 0.3.0 + nypm@0.6.5: + dependencies: + citty: 0.2.1 + pathe: 2.0.3 + tinyexec: 1.0.4 + object-deep-merge@2.0.0: {} object-inspect@1.13.4: {} @@ -9977,6 +10538,8 @@ snapshots: pathe@2.0.3: {} + perfect-debounce@2.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.2: {} @@ -9989,6 +10552,12 @@ snapshots: dependencies: find-up: 4.1.0 + pkg-types@2.3.0: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + pluralize@8.0.0: {} possible-typed-array-names@1.1.0: {} @@ -10049,6 +10618,11 @@ snapshots: quick-lru@5.1.1: {} + rc9@2.1.2: + dependencies: + defu: 6.1.6 + destr: 2.0.5 + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -10070,6 +10644,8 @@ snapshots: dependencies: picomatch: 2.3.2 + readdirp@5.0.0: {} + readme-badger@0.3.0: dependencies: balanced-match: 1.0.2 @@ -10169,6 +10745,23 @@ snapshots: dependencies: glob: 7.2.3 + rolldown-plugin-dts@0.22.5(rolldown@1.0.0-rc.11(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2))(typescript@6.0.2): + dependencies: + '@babel/generator': 8.0.0-rc.2 + '@babel/helper-validator-identifier': 8.0.0-rc.2 + '@babel/parser': 8.0.0-rc.2 + '@babel/types': 8.0.0-rc.2 + ast-kit: 3.0.0-beta.1 + birpc: 4.0.0 + dts-resolver: 2.1.3 + get-tsconfig: 4.13.7 + obug: 2.1.1 + rolldown: 1.0.0-rc.11(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + optionalDependencies: + typescript: 6.0.2 + transitivePeerDependencies: + - oxc-resolver + rolldown-plugin-dts@0.23.2(rolldown@1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2))(typescript@6.0.2): dependencies: '@babel/generator': 8.0.0-rc.3 @@ -10187,6 +10780,30 @@ snapshots: transitivePeerDependencies: - oxc-resolver + rolldown@1.0.0-rc.11(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): + dependencies: + '@oxc-project/types': 0.122.0 + '@rolldown/pluginutils': 1.0.0-rc.11 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.11 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.11 + '@rolldown/binding-darwin-x64': 1.0.0-rc.11 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.11 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.11 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.11 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.11 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.11 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.11(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.11 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.11 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + rolldown@1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): dependencies: '@oxc-project/types': 0.122.0 @@ -10624,6 +11241,35 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 + tsdown@0.21.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(synckit@0.11.12)(typescript@6.0.2): + dependencies: + ansis: 4.2.0 + cac: 7.0.0 + defu: 6.1.6 + empathic: 2.0.0 + hookable: 6.1.0 + import-without-cache: 0.2.5 + obug: 2.1.1 + picomatch: 4.0.4 + rolldown: 1.0.0-rc.11(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + rolldown-plugin-dts: 0.22.5(rolldown@1.0.0-rc.11(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2))(typescript@6.0.2) + semver: 7.7.4 + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + tree-kill: 1.2.2 + unconfig-core: 7.5.0 + unrun: 0.2.34(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(synckit@0.11.12) + optionalDependencies: + typescript: 6.0.2 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + - '@ts-macro/tsc' + - '@typescript/native-preview' + - oxc-resolver + - synckit + - vue-tsc + tsdown@0.21.7(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(synckit@0.11.12)(typescript@6.0.2): dependencies: ansis: 4.2.0 @@ -10674,6 +11320,8 @@ snapshots: '@turbo/windows-64': 2.9.5 '@turbo/windows-arm64': 2.9.5 + typanion@3.14.0: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -10869,6 +11517,22 @@ snapshots: validate-npm-package-name@7.0.2: {} + vite@8.0.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.8 + rolldown: 1.0.0-rc.11(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 20.19.39 + fsevents: 2.3.3 + jiti: 2.6.1 + yaml: 2.8.3 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + vite@8.0.8(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 @@ -10882,6 +11546,33 @@ snapshots: jiti: 2.6.1 yaml: 2.8.3 + vitest@4.1.1(@types/node@20.19.39)(vite@8.0.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3)): + dependencies: + '@vitest/expect': 4.1.1 + '@vitest/mocker': 4.1.1(vite@8.0.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.1 + '@vitest/runner': 4.1.1 + '@vitest/snapshot': 4.1.1 + '@vitest/spy': 4.1.1 + '@vitest/utils': 4.1.1 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 8.0.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.19.39 + transitivePeerDependencies: + - msw + vitest@4.1.4(@types/node@20.19.39)(vite@8.0.8(@types/node@20.19.39)(jiti@2.6.1)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.4 @@ -11141,4 +11832,6 @@ snapshots: grammex: 3.1.12 graphmatch: 1.1.1 + zod@3.25.76: {} + zwitch@2.0.4: {}