From 0658bfd40c01c0923a66180b34e10f27f9c30eec Mon Sep 17 00:00:00 2001 From: maxnorm Date: Mon, 25 May 2026 20:45:32 -0400 Subject: [PATCH] refactor to ts --- cli/bin/compose.js | 3 - cli/bin/compose.ts | 6 + cli/eslint.config.js | 24 +- cli/index.js | 56 - cli/index.ts | 64 + cli/package.json | 21 +- cli/scripts/generate-templates-config.js | 142 -- cli/scripts/generate-templates-config.ts | 203 ++ cli/src/commands/{init.js => init.ts} | 104 +- cli/src/commands/listTemplates.js | 23 - cli/src/commands/listTemplates.ts | 17 + cli/src/commands/{update.js => update.ts} | 10 +- cli/src/commands/version.js | 9 - cli/src/commands/version.ts | 5 + cli/src/config/constants.js | 26 - cli/src/config/constants.ts | 19 + cli/src/config/validateTemplatesConfig.js | 38 - cli/src/config/validateTemplatesConfig.ts | 71 + cli/src/context/types.ts | 31 + .../{initPrompts.js => initPrompts.ts} | 38 +- .../frameworks/{foundry.js => foundry.ts} | 42 +- .../frameworks/{hardhat.js => hardhat.ts} | 57 +- cli/src/scaffold/scaffold.js | 49 - cli/src/scaffold/scaffold.ts | 77 + cli/src/scaffold/utils/fileManager.js | 75 - cli/src/scaffold/utils/fileManager.ts | 87 + .../{packageOrderer.js => packageOrderer.ts} | 17 +- cli/src/scaffold/utils/templateLoader.js | 51 - cli/src/scaffold/utils/templateLoader.ts | 87 + .../{tokenReplace.js => tokenReplace.ts} | 22 +- ...seAsciiHeader.js => composeAsciiHeader.ts} | 8 +- cli/src/utils/{errors.js => errors.ts} | 11 +- cli/src/utils/exec.js | 24 - cli/src/utils/exec.ts | 28 + cli/src/utils/helpText.js | 29 - cli/src/utils/helpText.ts | 32 + cli/src/utils/{logger.js => logger.ts} | 20 +- cli/src/utils/prompts/initUtils.js | 29 - cli/src/utils/prompts/initUtils.ts | 46 + cli/test/integration/cliEntry.test.js | 35 - cli/test/integration/cliEntry.test.ts | 43 + ...iants.test.js => scaffoldVariants.test.ts} | 91 +- .../unit/{errors.test.js => errors.test.ts} | 37 +- ...ileManager.test.js => fileManager.test.ts} | 49 +- ...nitOptions.test.js => initOptions.test.ts} | 6 +- ...nitPrompts.test.js => initPrompts.test.ts} | 25 +- ...Orderer.test.js => packageOrderer.test.ts} | 16 +- ...eLoader.test.js => templateLoader.test.ts} | 14 +- cli/test/unit/templateSnapshot.test.js | 18 - cli/test/unit/templateSnapshot.test.ts | 30 + ...enReplace.test.js => tokenReplace.test.ts} | 31 +- cli/test/unit/validateTemplatesConfig.test.js | 19 - cli/test/unit/validateTemplatesConfig.test.ts | 30 + cli/test/unit/versionCommand.test.js | 18 - cli/test/unit/versionCommand.test.ts | 18 + cli/tsconfig.json | 29 + package-lock.json | 1946 ++++++++++------- package.json | 7 +- 58 files changed, 2495 insertions(+), 1668 deletions(-) delete mode 100755 cli/bin/compose.js create mode 100644 cli/bin/compose.ts delete mode 100755 cli/index.js create mode 100644 cli/index.ts delete mode 100644 cli/scripts/generate-templates-config.js create mode 100644 cli/scripts/generate-templates-config.ts rename cli/src/commands/{init.js => init.ts} (56%) delete mode 100644 cli/src/commands/listTemplates.js create mode 100644 cli/src/commands/listTemplates.ts rename cli/src/commands/{update.js => update.ts} (50%) delete mode 100644 cli/src/commands/version.js create mode 100644 cli/src/commands/version.ts delete mode 100644 cli/src/config/constants.js create mode 100644 cli/src/config/constants.ts delete mode 100644 cli/src/config/validateTemplatesConfig.js create mode 100644 cli/src/config/validateTemplatesConfig.ts create mode 100644 cli/src/context/types.ts rename cli/src/prompts/{initPrompts.js => initPrompts.ts} (68%) rename cli/src/scaffold/frameworks/{foundry.js => foundry.ts} (61%) rename cli/src/scaffold/frameworks/{hardhat.js => hardhat.ts} (51%) delete mode 100644 cli/src/scaffold/scaffold.js create mode 100644 cli/src/scaffold/scaffold.ts delete mode 100644 cli/src/scaffold/utils/fileManager.js create mode 100644 cli/src/scaffold/utils/fileManager.ts rename cli/src/scaffold/utils/{packageOrderer.js => packageOrderer.ts} (67%) delete mode 100644 cli/src/scaffold/utils/templateLoader.js create mode 100644 cli/src/scaffold/utils/templateLoader.ts rename cli/src/scaffold/utils/{tokenReplace.js => tokenReplace.ts} (68%) rename cli/src/utils/{composeAsciiHeader.js => composeAsciiHeader.ts} (86%) rename cli/src/utils/{errors.js => errors.ts} (64%) delete mode 100644 cli/src/utils/exec.js create mode 100644 cli/src/utils/exec.ts delete mode 100644 cli/src/utils/helpText.js create mode 100644 cli/src/utils/helpText.ts rename cli/src/utils/{logger.js => logger.ts} (53%) delete mode 100644 cli/src/utils/prompts/initUtils.js create mode 100644 cli/src/utils/prompts/initUtils.ts delete mode 100644 cli/test/integration/cliEntry.test.js create mode 100644 cli/test/integration/cliEntry.test.ts rename cli/test/integration/{scaffoldVariants.test.js => scaffoldVariants.test.ts} (61%) rename cli/test/unit/{errors.test.js => errors.test.ts} (57%) rename cli/test/unit/{fileManager.test.js => fileManager.test.ts} (67%) rename cli/test/unit/{initOptions.test.js => initOptions.test.ts} (84%) rename cli/test/unit/{initPrompts.test.js => initPrompts.test.ts} (63%) rename cli/test/unit/{packageOrderer.test.js => packageOrderer.test.ts} (62%) rename cli/test/unit/{templateLoader.test.js => templateLoader.test.ts} (83%) delete mode 100644 cli/test/unit/templateSnapshot.test.js create mode 100644 cli/test/unit/templateSnapshot.test.ts rename cli/test/unit/{tokenReplace.test.js => tokenReplace.test.ts} (50%) delete mode 100644 cli/test/unit/validateTemplatesConfig.test.js create mode 100644 cli/test/unit/validateTemplatesConfig.test.ts delete mode 100644 cli/test/unit/versionCommand.test.js create mode 100644 cli/test/unit/versionCommand.test.ts create mode 100644 cli/tsconfig.json diff --git a/cli/bin/compose.js b/cli/bin/compose.js deleted file mode 100755 index 633e820d..00000000 --- a/cli/bin/compose.js +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node - -require("../index.js"); diff --git a/cli/bin/compose.ts b/cli/bin/compose.ts new file mode 100644 index 00000000..63559497 --- /dev/null +++ b/cli/bin/compose.ts @@ -0,0 +1,6 @@ +#!/usr/bin/env node + +import { main } from "../index.js"; +import { exitWithError } from "../src/utils/errors.js"; + +main().catch(exitWithError); diff --git a/cli/eslint.config.js b/cli/eslint.config.js index 95840019..847507b6 100644 --- a/cli/eslint.config.js +++ b/cli/eslint.config.js @@ -1,25 +1,17 @@ -const js = require("@eslint/js"); +import js from "@eslint/js"; +import tseslint from "typescript-eslint"; -module.exports = [ +export default [ { - ignores: ["node_modules/**", "src/templates/**"], + ignores: ["node_modules/**", "dist/**", "src/templates/**"], }, js.configs.recommended, + ...tseslint.configs.recommended, { - files: ["**/*.js"], - languageOptions: { - ecmaVersion: "latest", - sourceType: "script", - globals: { - console: "readonly", - process: "readonly", - __dirname: "readonly", - module: "readonly", - require: "readonly", - }, - }, + files: ["**/*.ts"], rules: { - "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], }, }, ]; diff --git a/cli/index.js b/cli/index.js deleted file mode 100755 index ca16455d..00000000 --- a/cli/index.js +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env node - -const minimist = require("minimist"); -const pkg = require("./package.json"); -const { logger } = require("./src/utils/logger"); -const { exitWithError } = require("./src/utils/errors"); -const { runInitCommand } = require("./src/commands/init"); -const { runVersionCommand } = require("./src/commands/version"); -const { runUpdateCommand } = require("./src/commands/update"); -const { runListTemplatesCommand } = require("./src/commands/listTemplates"); -const { HELP_TEXT } = require("./src/utils/helpText"); - -async function main() { - const argv = minimist(process.argv.slice(2), { - alias: { - v: "version", - h: "help", - n: "name", - }, - boolean: ["version", "help", "yes"], - string: ["name", "template", "framework", "language"], - }); - - const [command = ""] = argv._; - - if (argv.version) { - runVersionCommand(pkg.version); - return; - } - - if (argv.help || !command) { - logger.plain(HELP_TEXT.trim()); - return; - } - - if (command === "init") { - await runInitCommand(argv); - return; - } - - if (command === "update") { - await runUpdateCommand(pkg.name); - return; - } - - if (command === "templates") { - await runListTemplatesCommand(); - return; - } - - throw new Error(`Unknown command: ${command}. Run 'compose --help' for available commands.`); -} - -main().catch((error) => { - exitWithError(error); -}); diff --git a/cli/index.ts b/cli/index.ts new file mode 100644 index 00000000..08a75e2c --- /dev/null +++ b/cli/index.ts @@ -0,0 +1,64 @@ +#!/usr/bin/env node + +import { Command } from "commander"; +import { createRequire } from "node:module"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const require = createRequire(import.meta.url); + +const pkg = require(resolve(__dirname, "package.json")) as { + version: string; + name: string; +}; + +import { runInitCommand } from "./src/commands/init.js"; +import { runUpdateCommand } from "./src/commands/update.js"; +import { runListTemplatesCommand } from "./src/commands/listTemplates.js"; + +const program = new Command(); + +program + .name("compose") + .description( + "CLI for building, deploying, and managing diamond smart contracts", + ) + .version(pkg.version, "-v, --version", "Print CLI version"); + +program + .command("init") + .description("Scaffold a new Compose diamond project") + .option("-n, --name ", "Project name") + .option("--template ", "Template ID") + .option("--framework ", "Project framework (foundry | hardhat)") + .option( + "--language ", + "Project language (javascript | typescript)", + ) + .option("--hardhat-project-type ", "Hardhat project type") + .option("--install-deps", "Install dependencies") + .option("--no-install-deps", "Skip dependency installation") + .option("-y, --yes", "Skip prompts and use defaults") + .action(async (options) => { + await runInitCommand(options); + }); + +program + .command("templates") + .description("List available templates") + .action(async () => { + await runListTemplatesCommand(); + }); + +program + .command("update") + .description("Update the CLI to the latest version") + .action(async () => { + await runUpdateCommand(pkg.name); + }); + +export async function main(): Promise { + await program.parseAsync(process.argv); +} diff --git a/cli/package.json b/cli/package.json index 3ecd3e24..bbe409b3 100644 --- a/cli/package.json +++ b/cli/package.json @@ -2,36 +2,37 @@ "name": "@perfect-abstractions/compose-cli", "version": "0.0.5", "description": "CLI to scaffold Compose facet-based diamond projects", - "main": "index.js", + "type": "module", "bin": { "compose": "bin/compose.js" }, - "type": "commonjs", "scripts": { + "compose": "tsx bin/compose.ts", + "build": "tsc", "lint": "eslint .", - "test": "node --test \"test/**/*.test.js\"", - "test:unit": "node --test \"test/unit/**/*.test.js\"", - "test:integration": "node --test \"test/integration/**/*.test.js\"", + "test": "tsx --test \"test/**/*.test.ts\"", + "test:unit": "tsx --test \"test/unit/**/*.test.ts\"", + "test:integration": "tsx --test \"test/integration/**/*.test.ts\"", "check": "npm run lint && npm run test", - "build:templates": "node scripts/generate-templates-config.js", + "build:templates": "tsx scripts/generate-templates-config.ts", "pack:check": "npm pack --dry-run", - "prepublishOnly": "npm run check && npm run pack:check", + "prepublishOnly": "npm run check && npm run build && npm run pack:check", "prepare:lib": "git submodule update --init --recursive" }, "engines": { "node": ">=20" }, "files": [ - "index.js", + "dist/", "src/", "!src/templates/**/lib/", "README.md", "LICENSE.md" ], "dependencies": { + "commander": "^13.1.0", "fs-extra": "^11.3.3", "inquirer": "^13.3.0", - "minimist": "^1.2.8", "picocolors": "^1.1.1" }, "devDependencies": { @@ -50,7 +51,9 @@ "forge-std": "github:foundry-rs/forge-std#v1.9.4", "hardhat": "^3.1.10", "mocha": "^11.7.5", + "tsx": "^4.19.0", "typescript": "~5.8.0", + "typescript-eslint": "^8.30.0", "viem": "^2.47.0" }, "keywords": [ diff --git a/cli/scripts/generate-templates-config.js b/cli/scripts/generate-templates-config.js deleted file mode 100644 index b807b7d7..00000000 --- a/cli/scripts/generate-templates-config.js +++ /dev/null @@ -1,142 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const { validateTemplatesConfig } = require("../src/config/validateTemplatesConfig"); - -const ROOT_DIR = path.resolve(__dirname, ".."); -const TEMPLATES_ROOT = path.join(ROOT_DIR, "src", "templates"); -const OUTPUT_CONFIG_PATH = path.join(ROOT_DIR, "src", "config", "templates.json"); - -function readJsonFile(filePath) { - const content = fs.readFileSync(filePath, "utf8"); - return JSON.parse(content); -} - -function parseVariantId(templateId, variantId) { - const suffix = variantId.startsWith(`${templateId}-`) - ? variantId.slice(templateId.length + 1) - : variantId; - - const [framework, ...rest] = suffix.split("-"); - - return { - framework, - projectType: rest.length > 0 ? rest.join("-") : undefined, - }; -} - -function inferLanguageFromPath(relativePath) { - if (relativePath.includes("/ts/")) { - return "typescript"; - } - - if (relativePath.includes("/js/")) { - return "javascript"; - } - - return undefined; -} - -function buildVariantPath(templateId, framework, projectType, overridePath) { - if (overridePath) { - return overridePath; - } - - if (framework === "foundry") { - return `templates/${templateId}/${framework}`; - } - - if (!projectType) { - return `templates/${templateId}/${framework}`; - } - - return `templates/${templateId}/${framework}/ts/${projectType}`; -} - -function loadTemplateManifests() { - const entries = fs.readdirSync(TEMPLATES_ROOT, { withFileTypes: true }); - const templates = []; - - entries.forEach((entry) => { - if (!entry.isDirectory()) { - return; - } - - const templateDir = path.join(TEMPLATES_ROOT, entry.name); - const manifestPath = path.join(templateDir, "template.json"); - - if (!fs.existsSync(manifestPath)) { - return; - } - - const manifest = readJsonFile(manifestPath); - templates.push(manifest); - }); - - return templates; -} - -function buildTemplatesConfig() { - const templateManifests = loadTemplateManifests(); - - const templates = templateManifests.map((manifest) => { - const templateId = manifest.id; - - const variants = (manifest.variants || []).map((variantId) => { - const { framework, projectType } = parseVariantId(templateId, variantId); - - const pathValue = buildVariantPath( - templateId, - framework, - projectType, - ); - - const language = inferLanguageFromPath(pathValue); - - return { - id: variantId, - framework, - path: pathValue, - ...(language ? { language } : {}), - ...(projectType ? { projectType } : {}), - }; - }); - - return { - id: templateId, - name: manifest.name, - description: manifest.description, - variants, - }; - }); - - const config = { - templates, - defaultTemplateId: templateManifests[0] ? templateManifests[0].id : "default", - }; - - validateTemplatesConfig(config); - - return config; -} - -function writeTemplatesConfig(config) { - const json = `${JSON.stringify(config, null, 2)}\n`; - fs.writeFileSync(OUTPUT_CONFIG_PATH, json, "utf8"); -} - -function main() { - try { - const config = buildTemplatesConfig(); - writeTemplatesConfig(config); - console.log(`Generated templates config at ${path.relative(ROOT_DIR, OUTPUT_CONFIG_PATH)}`); - } catch (error) { - console.error("Failed to generate templates config:"); - console.error(error.message || error); - process.exitCode = 1; - } -} - -if (require.main === module) { - main(); -} - diff --git a/cli/scripts/generate-templates-config.ts b/cli/scripts/generate-templates-config.ts new file mode 100644 index 00000000..cbd4e058 --- /dev/null +++ b/cli/scripts/generate-templates-config.ts @@ -0,0 +1,203 @@ +import { createRequire } from "node:module"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; +import fs from "node:fs"; +import path from "node:path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const require = createRequire(import.meta.url); + +const { validateTemplatesConfig } = require(resolve( + __dirname, + "..", + "src", + "config", + "validateTemplatesConfig.js" +)) as { validateTemplatesConfig: (config: unknown) => boolean }; + +const ROOT_DIR = resolve(__dirname, ".."); +const TEMPLATES_ROOT = path.join(ROOT_DIR, "src", "templates"); +const OUTPUT_CONFIG_PATH = path.join( + ROOT_DIR, + "src", + "config", + "templates.json" +); + +type TemplateManifest = { + id: string; + name: string; + description?: string; + variants: string[]; +}; + +type VariantEntry = { + id: string; + framework: string; + path: string; + language?: string; + projectType?: string; +}; + +type TemplateEntry = { + id: string; + name: string; + description?: string; + variants: VariantEntry[]; +}; + +type TemplatesConfig = { + templates: TemplateEntry[]; + defaultTemplateId: string; +}; + +function parseVariantId(templateId: string, variantId: string) { + const suffix = variantId.startsWith(`${templateId}-`) + ? variantId.slice(templateId.length + 1) + : variantId; + + const [framework, ...rest] = suffix.split("-"); + + return { + framework, + projectType: rest.length > 0 ? rest.join("-") : undefined, + }; +} + +function inferLanguageFromPath(relativePath: string) { + if (relativePath.includes("/ts/")) { + return "typescript"; + } + + if (relativePath.includes("/js/")) { + return "javascript"; + } + + return undefined; +} + +function buildVariantPath( + templateId: string, + framework: string, + projectType?: string, + overridePath?: string +) { + if (overridePath) { + return overridePath; + } + + if (framework === "foundry") { + return `templates/${templateId}/${framework}`; + } + + if (!projectType) { + return `templates/${templateId}/${framework}`; + } + + return `templates/${templateId}/${framework}/ts/${projectType}`; +} + +function loadTemplateManifests(): TemplateManifest[] { + const entries = fs.readdirSync(TEMPLATES_ROOT, { withFileTypes: true }); + const templates: TemplateManifest[] = []; + + entries.forEach((entry) => { + if (!entry.isDirectory()) { + return; + } + + const templateDir = path.join(TEMPLATES_ROOT, entry.name); + const manifestPath = path.join(templateDir, "template.json"); + + if (!fs.existsSync(manifestPath)) { + return; + } + + const content = fs.readFileSync(manifestPath, "utf8"); + const manifest = JSON.parse(content) as TemplateManifest; + templates.push(manifest); + }); + + return templates; +} + +function buildTemplatesConfig(): TemplatesConfig { + const templateManifests = loadTemplateManifests(); + + const templates: TemplateEntry[] = templateManifests.map((manifest) => { + const templateId = manifest.id; + + const variants: VariantEntry[] = (manifest.variants || []).map( + (variantId: string) => { + const { framework, projectType } = parseVariantId( + templateId, + variantId + ); + + const pathValue = buildVariantPath( + templateId, + framework, + projectType + ); + + const language = inferLanguageFromPath(pathValue); + + const variant: VariantEntry = { + id: variantId, + framework, + path: pathValue, + }; + + if (language) { + variant.language = language; + } + if (projectType) { + variant.projectType = projectType; + } + + return variant; + } + ); + + return { + id: templateId, + name: manifest.name, + description: manifest.description, + variants, + }; + }); + + const config: TemplatesConfig = { + templates, + defaultTemplateId: + templateManifests[0] ? templateManifests[0].id : "default", + }; + + validateTemplatesConfig(config); + + return config; +} + +function writeTemplatesConfig(config: TemplatesConfig): void { + const json = `${JSON.stringify(config, null, 2)}\n`; + fs.writeFileSync(OUTPUT_CONFIG_PATH, json, "utf8"); +} + +function main(): void { + try { + const config = buildTemplatesConfig(); + writeTemplatesConfig(config); + console.log( + `Generated templates config at ${path.relative(ROOT_DIR, OUTPUT_CONFIG_PATH)}` + ); + } catch (error) { + console.error("Failed to generate templates config:"); + console.error( + error instanceof Error ? error.message : String(error) + ); + process.exitCode = 1; + } +} + +main(); diff --git a/cli/src/commands/init.js b/cli/src/commands/init.ts similarity index 56% rename from cli/src/commands/init.js rename to cli/src/commands/init.ts index 9a57f76d..03e8eb07 100644 --- a/cli/src/commands/init.js +++ b/cli/src/commands/init.ts @@ -1,31 +1,49 @@ -const fs = require("fs-extra"); -const path = require("node:path"); -const { askInitPrompts } = require("../prompts/initPrompts"); -const { logger } = require("../utils/logger"); -const { COMPOSE_DOCS_URL, COMPOSE_REPO_URL } = require("../config/constants"); -const { loadTemplateConfig, pickVariant, resolveTemplatePath } = require("../scaffold/utils/templateLoader"); -const { scaffold } = require("../scaffold/scaffold"); -const { COMPOSE_HEADER } = require("../utils/composeAsciiHeader"); - -function normalizeInitOptions(argv) { - const options = { - projectName: argv.name || "", - template: argv.template || "", - framework: argv.framework || "", - language: argv.language, - hardhatProjectType: argv.hardhatProjectType, - installDeps: argv["install-deps"], +import fs from "fs-extra"; +import path from "node:path"; +import { askInitPrompts } from "../prompts/initPrompts.js"; +import { logger } from "../utils/logger.js"; +import { + COMPOSE_DOCS_URL, + COMPOSE_REPO_URL, +} from "../config/constants.js"; +import { + loadTemplateConfig, + pickVariant, + resolveTemplatePath, +} from "../scaffold/utils/templateLoader.js"; +import { scaffold } from "../scaffold/scaffold.js"; +import { COMPOSE_HEADER } from "../utils/composeAsciiHeader.js"; + +type InitOptions = { + projectName: string; + template: string; + framework: string; + language?: string; + hardhatProjectType?: string; + installDeps?: boolean; + yes: boolean; +}; + +export function normalizeInitOptions(argv: Record): InitOptions { + const options: InitOptions = { + projectName: (argv.name as string) || "", + template: (argv.template as string) || "", + framework: (argv.framework as string) || "", + language: argv.language as string | undefined, + hardhatProjectType: argv.hardhatProjectType as string | undefined, + installDeps: (argv.installDeps ?? argv["install-deps"]) as boolean | undefined, yes: Boolean(argv.yes), }; return options; } -async function ensureBinaryExists(binaryName) { +async function ensureBinaryExists(binaryName: string): Promise { const hasPath = process.env.PATH || ""; const separator = process.platform === "win32" ? ";" : ":"; const paths = hasPath.split(separator); - const extensions = process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""]; + const extensions = + process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""]; for (const currentPath of paths) { for (const extension of extensions) { @@ -39,12 +57,12 @@ async function ensureBinaryExists(binaryName) { return false; } -async function preflightChecks(options) { +async function preflightChecks(options: InitOptions): Promise { if (options.framework === "foundry") { const forgeExists = await ensureBinaryExists("forge"); if (!forgeExists) { throw new Error( - "forge not found in PATH. Please install Foundry and try again.", + "forge not found in PATH. Please install Foundry and try again." ); } } @@ -52,18 +70,25 @@ async function preflightChecks(options) { if (options.framework === "hardhat" && options.installDeps !== false) { const npmExists = await ensureBinaryExists("npm"); if (!npmExists) { - throw new Error("npm not found in PATH. Please install Node.js (with npm) and try again."); + throw new Error( + "npm not found in PATH. Please install Node.js (with npm) and try again." + ); } } } -async function collectInitOptions(argv) { +async function collectInitOptions( + argv: Record +): Promise { const normalized = normalizeInitOptions(argv); if (normalized.yes) { if (!normalized.projectName) { normalized.projectName = "my-diamond"; } + if (!normalized.template) { + normalized.template = "default"; + } if (typeof normalized.installDeps !== "boolean") { normalized.installDeps = true; } @@ -80,7 +105,8 @@ async function collectInitOptions(argv) { const framework = answers.framework || normalized.framework; const language = - normalized.language || (framework === "hardhat" ? "typescript" : normalized.language); + normalized.language || + (framework === "hardhat" ? "typescript" : normalized.language); return { ...normalized, @@ -88,18 +114,22 @@ async function collectInitOptions(argv) { template: answers.template || normalized.template, framework, language, - hardhatProjectType: answers.hardhatProjectType || normalized.hardhatProjectType, - installDeps: typeof answers.installDeps === "boolean" ? answers.installDeps : true, + hardhatProjectType: + answers.hardhatProjectType || normalized.hardhatProjectType, + installDeps: + typeof answers.installDeps === "boolean" ? answers.installDeps : true, }; } -function printInitHeader() { +function printInitHeader(): void { logger.info(COMPOSE_HEADER); logger.info("Scaffold your diamond smart contracts project with Compose"); logger.info(`Explore our library: ${COMPOSE_DOCS_URL}\n`); } -async function runInitCommand(argv) { +export async function runInitCommand( + argv: Record +): Promise { printInitHeader(); const initOptions = await collectInitOptions(argv); await preflightChecks(initOptions); @@ -114,14 +144,14 @@ async function runInitCommand(argv) { const templatePath = resolveTemplatePath(selectedVariant); - const { projectDir, displayName, nextSteps } = await scaffold({ projectName: initOptions.projectName, templatePath, options: { framework: selectedVariant.framework, language: selectedVariant.language, - hardhatProjectType: initOptions.hardhatProjectType || selectedVariant.projectType, + hardhatProjectType: + initOptions.hardhatProjectType || selectedVariant.projectType, installDeps: initOptions.installDeps, }, }); @@ -131,6 +161,7 @@ async function runInitCommand(argv) { let stepCount = 1; if (path.resolve(projectDir) !== process.cwd()) { logger.plain(`${stepCount}. cd ${displayName}`); + stepCount++; } for (const step of nextSteps) { logger.plain(`${stepCount}. ${step}`); @@ -139,11 +170,10 @@ async function runInitCommand(argv) { logger.plain(""); logger.info("You're all set. We hope you'll Compose something great!\n"); - logger.brightYellow(`If this helped you, please give us a star on GitHub:\n✨ ${COMPOSE_REPO_URL} ✨\n`); - logger.warn(`Please report any issues or feedback:\n${COMPOSE_REPO_URL}/issues\n`); + logger.brightYellow( + `If this helped you, please give us a star on GitHub:\n✨ ${COMPOSE_REPO_URL} ✨\n` + ); + logger.warn( + `Please report any issues or feedback:\n${COMPOSE_REPO_URL}/issues\n` + ); } - -module.exports = { - runInitCommand, - normalizeInitOptions, -}; diff --git a/cli/src/commands/listTemplates.js b/cli/src/commands/listTemplates.js deleted file mode 100644 index 3a3c175c..00000000 --- a/cli/src/commands/listTemplates.js +++ /dev/null @@ -1,23 +0,0 @@ -const { loadTemplateConfig } = require("../scaffold/utils/templateLoader"); -const { logger } = require("../utils/logger"); - -async function runListTemplatesCommand() { - const config = await loadTemplateConfig(); - - config.templates.forEach((template) => { - logger.plain(`${template.id} - ${template.name}`); - template.variants.forEach((variant) => { - const meta = [ - variant.framework, - variant.language, - variant.projectType, - ].filter(Boolean).join(", "); - - logger.plain(` - ${variant.id}${meta ? ` (${meta})` : ""}`); - }); - }); -} - -module.exports = { - runListTemplatesCommand, -}; diff --git a/cli/src/commands/listTemplates.ts b/cli/src/commands/listTemplates.ts new file mode 100644 index 00000000..315266df --- /dev/null +++ b/cli/src/commands/listTemplates.ts @@ -0,0 +1,17 @@ +import { loadTemplateConfig } from "../scaffold/utils/templateLoader.js"; +import { logger } from "../utils/logger.js"; + +export async function runListTemplatesCommand(): Promise { + const config = await loadTemplateConfig(); + + config.templates.forEach((template) => { + logger.plain(`${template.id} - ${template.name}`); + template.variants.forEach((variant) => { + const meta = [variant.framework, variant.language, variant.projectType] + .filter(Boolean) + .join(", "); + + logger.plain(` - ${variant.id}${meta ? ` (${meta})` : ""}`); + }); + }); +} diff --git a/cli/src/commands/update.js b/cli/src/commands/update.ts similarity index 50% rename from cli/src/commands/update.js rename to cli/src/commands/update.ts index 623d0ea4..79916a4d 100644 --- a/cli/src/commands/update.js +++ b/cli/src/commands/update.ts @@ -1,14 +1,10 @@ -const { runCommand } = require("../utils/exec"); -const { logger } = require("../utils/logger"); +import { runCommand } from "../utils/exec.js"; +import { logger } from "../utils/logger.js"; -async function runUpdateCommand(packageName) { +export async function runUpdateCommand(packageName: string): Promise { logger.info("Updating CLI to latest..."); await runCommand("npm", ["install", "-g", `${packageName}@latest`], { cwd: process.cwd(), }); logger.success("Update complete."); } - -module.exports = { - runUpdateCommand, -}; diff --git a/cli/src/commands/version.js b/cli/src/commands/version.js deleted file mode 100644 index 0e4cd959..00000000 --- a/cli/src/commands/version.js +++ /dev/null @@ -1,9 +0,0 @@ -const { logger } = require("../utils/logger"); - -function runVersionCommand(version) { - logger.plain(version); -} - -module.exports = { - runVersionCommand, -}; diff --git a/cli/src/commands/version.ts b/cli/src/commands/version.ts new file mode 100644 index 00000000..d4e1787c --- /dev/null +++ b/cli/src/commands/version.ts @@ -0,0 +1,5 @@ +import { logger } from "../utils/logger.js"; + +export function runVersionCommand(version: string): void { + logger.plain(version); +} diff --git a/cli/src/config/constants.js b/cli/src/config/constants.js deleted file mode 100644 index 26010f50..00000000 --- a/cli/src/config/constants.js +++ /dev/null @@ -1,26 +0,0 @@ -const path = require("node:path"); - -const COMPOSE_REPO_URL = "https://github.com/Perfect-Abstractions/Compose"; -const COMPOSE_DOCS_URL = "https://compose.diamonds/"; - -const COMPOSE_NPM_PACKAGE = "@perfect-abstractions/compose"; -const COMPOSE_NPM_VERSION = "latest"; - -const COMPOSE_FOUNDRY_DEP = "Perfect-Abstractions/Compose"; - -const DEFAULT_TEMPLATE_ID = "default"; -const DEFAULT_FRAMEWORK = "foundry"; - -const TEMPLATE_REGISTRY_PATH = path.join(__dirname, "templates.json"); - -module.exports = { - COMPOSE_REPO_URL, - COMPOSE_DOCS_URL, - COMPOSE_NPM_PACKAGE, - COMPOSE_NPM_VERSION, - COMPOSE_FOUNDRY_DEP, - DEFAULT_TEMPLATE_ID, - DEFAULT_FRAMEWORK, - TEMPLATE_REGISTRY_PATH, -}; - diff --git a/cli/src/config/constants.ts b/cli/src/config/constants.ts new file mode 100644 index 00000000..30f4adbe --- /dev/null +++ b/cli/src/config/constants.ts @@ -0,0 +1,19 @@ +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +export const COMPOSE_REPO_URL = + "https://github.com/Perfect-Abstractions/Compose"; +export const COMPOSE_DOCS_URL = "https://compose.diamonds/"; + +export const COMPOSE_NPM_PACKAGE = "@perfect-abstractions/compose"; +export const COMPOSE_NPM_VERSION = "latest"; + +export const COMPOSE_FOUNDRY_DEP = "Perfect-Abstractions/Compose"; + +export const DEFAULT_TEMPLATE_ID = "default"; +export const DEFAULT_FRAMEWORK = "foundry"; + +export const TEMPLATE_REGISTRY_PATH = resolve(__dirname, "templates.json"); diff --git a/cli/src/config/validateTemplatesConfig.js b/cli/src/config/validateTemplatesConfig.js deleted file mode 100644 index f155e929..00000000 --- a/cli/src/config/validateTemplatesConfig.js +++ /dev/null @@ -1,38 +0,0 @@ -function ensureString(value, keyPath) { - if (typeof value !== "string" || value.trim() === "") { - throw new Error(`Invalid templates config: ${keyPath} must be a non-empty string`); - } -} - -function validateTemplatesConfig(config) { - if (!config || typeof config !== "object") { - throw new Error("Invalid templates config: config root must be an object"); - } - - if (!Array.isArray(config.templates) || config.templates.length === 0) { - throw new Error("Invalid templates config: templates must be a non-empty array"); - } - - config.templates.forEach((template, index) => { - ensureString(template.id, `templates[${index}].id`); - ensureString(template.name, `templates[${index}].name`); - - if (!Array.isArray(template.variants) || template.variants.length === 0) { - throw new Error(`Invalid templates config: templates[${index}].variants must be a non-empty array`); - } - - template.variants.forEach((variant, variantIndex) => { - ensureString(variant.id, `templates[${index}].variants[${variantIndex}].id`); - ensureString(variant.framework, `templates[${index}].variants[${variantIndex}].framework`); - ensureString(variant.path, `templates[${index}].variants[${variantIndex}].path`); - }); - }); - - ensureString(config.defaultTemplateId, "defaultTemplateId"); - - return true; -} - -module.exports = { - validateTemplatesConfig, -}; diff --git a/cli/src/config/validateTemplatesConfig.ts b/cli/src/config/validateTemplatesConfig.ts new file mode 100644 index 00000000..37d31d48 --- /dev/null +++ b/cli/src/config/validateTemplatesConfig.ts @@ -0,0 +1,71 @@ +type TemplateVariant = { + id: string; + framework: string; + path: string; + language?: string; + projectType?: string; +}; + +type Template = { + id: string; + name: string; + description?: string; + variants: TemplateVariant[]; +}; + +type TemplatesConfig = { + templates: Template[]; + defaultTemplateId: string; +}; + +function ensureString(value: unknown, keyPath: string): asserts value is string { + if (typeof value !== "string" || value.trim() === "") { + throw new Error( + `Invalid templates config: ${keyPath} must be a non-empty string` + ); + } +} + +export function validateTemplatesConfig(config: unknown): config is TemplatesConfig { + if (!config || typeof config !== "object") { + throw new Error("Invalid templates config: config root must be an object"); + } + + const cfg = config as TemplatesConfig; + + if (!Array.isArray(cfg.templates) || cfg.templates.length === 0) { + throw new Error( + "Invalid templates config: templates must be a non-empty array" + ); + } + + cfg.templates.forEach((template, index) => { + ensureString(template.id, `templates[${index}].id`); + ensureString(template.name, `templates[${index}].name`); + + if ( + !Array.isArray(template.variants) || + template.variants.length === 0 + ) { + throw new Error( + `Invalid templates config: templates[${index}].variants must be a non-empty array` + ); + } + + template.variants.forEach((variant, variantIndex) => { + ensureString(variant.id, `templates[${index}].variants[${variantIndex}].id`); + ensureString( + variant.framework, + `templates[${index}].variants[${variantIndex}].framework` + ); + ensureString( + variant.path, + `templates[${index}].variants[${variantIndex}].path` + ); + }); + }); + + ensureString(cfg.defaultTemplateId, "defaultTemplateId"); + + return true; +} diff --git a/cli/src/context/types.ts b/cli/src/context/types.ts new file mode 100644 index 00000000..eec4b3e4 --- /dev/null +++ b/cli/src/context/types.ts @@ -0,0 +1,31 @@ +export type ComposeError = { + code: string; + message: string; + nativeError: unknown | null; +}; + +export type ModuleState = { + success: boolean; + result: T | null; + error: ComposeError | null; +}; + +export type ExecutionStatus = { + success: boolean; + stopped: boolean; + failedAt: string | null; + error: ComposeError | null; +}; + +export type ChildPipelineState = { + success: boolean; + state: Record; + status: ExecutionStatus; +}; + +export type ComposeContext = { + param: Record; + config: Record; + state: Record; + status: ExecutionStatus; +}; diff --git a/cli/src/prompts/initPrompts.js b/cli/src/prompts/initPrompts.ts similarity index 68% rename from cli/src/prompts/initPrompts.js rename to cli/src/prompts/initPrompts.ts index 9f1661a7..d5fa972d 100644 --- a/cli/src/prompts/initPrompts.js +++ b/cli/src/prompts/initPrompts.ts @@ -1,12 +1,34 @@ -const inquirer = require("inquirer").default; -const { getTemplateChoices, validateProjectLocation } = require("../utils/prompts/initUtils"); +import inquirer from "inquirer"; +import { + getTemplateChoices, + validateProjectLocation, +} from "../utils/prompts/initUtils.js"; -async function askInitPrompts(seed = {}) { - const answers = await inquirer.prompt([ +type InitOptionsSeed = { + name?: string; + template?: string; + framework?: string; + hardhatProjectType?: string; + installDeps?: boolean; +}; + +type InitAnswers = { + name: string; + template: string; + framework: string; + hardhatProjectType: string; + installDeps: boolean; +}; + +export async function askInitPrompts( + seed: InitOptionsSeed = {} +): Promise { + const answers = await inquirer.prompt([ { type: "input", name: "name", - message: 'Where would you like to initialize the project? ("." for current directory) ', + message: + 'Where would you like to initialize the project? ("." for current directory) ', default: seed.name || "my-first-diamond", when: () => !seed.name, validate: validateProjectLocation, @@ -60,9 +82,5 @@ async function askInitPrompts(seed = {}) { return { ...seed, ...answers, - }; + } as InitAnswers; } - -module.exports = { - askInitPrompts -}; diff --git a/cli/src/scaffold/frameworks/foundry.js b/cli/src/scaffold/frameworks/foundry.ts similarity index 61% rename from cli/src/scaffold/frameworks/foundry.js rename to cli/src/scaffold/frameworks/foundry.ts index db4c778b..c5694afb 100644 --- a/cli/src/scaffold/frameworks/foundry.js +++ b/cli/src/scaffold/frameworks/foundry.ts @@ -1,11 +1,27 @@ -const fs = require("fs-extra"); -const path = require("path"); -const { copyTemplate, getTemplateDisplayName } = require("../utils/fileManager"); -const { runCommand } = require("../../utils/exec"); -const { logger } = require("../../utils/logger"); -const { COMPOSE_FOUNDRY_DEP } = require("../../config/constants"); - -async function scaffoldFoundry(projectName, templatePath, projectDir, options) { +import fs from "fs-extra"; +import path from "node:path"; +import { + copyTemplate, + getTemplateDisplayName, +} from "../utils/fileManager.js"; +import { runCommand } from "../../utils/exec.js"; +import { logger } from "../../utils/logger.js"; +import { COMPOSE_FOUNDRY_DEP } from "../../config/constants.js"; + +type ScaffoldOptions = { + installDeps?: boolean; +}; + +type ScaffoldResult = { + nextSteps: string[]; +}; + +export async function scaffoldFoundry( + projectName: string, + templatePath: string, + projectDir: string, + options: ScaffoldOptions +): Promise { const shouldInstallDeps = Boolean(options.installDeps); logger.info(`Scaffolding Foundry project in "${projectDir}"…`); @@ -16,12 +32,13 @@ async function scaffoldFoundry(projectName, templatePath, projectDir, options) { if (shouldInstallDeps) { logger.info("Installing Compose dependencies with forge…"); - await runCommand("forge", ["install", COMPOSE_FOUNDRY_DEP], { cwd: projectDir }); + await runCommand("forge", ["install", COMPOSE_FOUNDRY_DEP], { + cwd: projectDir, + }); } else { logger.info("Skipping dependency installation... "); } - // Remove default Forge starter contracts/scripts/tests for replacement with our template. await Promise.all([ fs.remove(path.join(projectDir, "src")), fs.remove(path.join(projectDir, "test")), @@ -39,8 +56,3 @@ async function scaffoldFoundry(projectName, templatePath, projectDir, options) { return { nextSteps }; } - -module.exports = { - scaffoldFoundry, -}; - diff --git a/cli/src/scaffold/frameworks/hardhat.js b/cli/src/scaffold/frameworks/hardhat.ts similarity index 51% rename from cli/src/scaffold/frameworks/hardhat.js rename to cli/src/scaffold/frameworks/hardhat.ts index 348387f2..2414785a 100644 --- a/cli/src/scaffold/frameworks/hardhat.js +++ b/cli/src/scaffold/frameworks/hardhat.ts @@ -1,19 +1,48 @@ -const fs = require("fs-extra"); -const path = require("node:path"); -const { copyTemplate, readJson, writeJson } = require("../utils/fileManager"); -const { orderPackageJsonWithDepsBeforeDevDeps } = require("../utils/packageOrderer"); -const { runCommand } = require("../../utils/exec"); -const { logger } = require("../../utils/logger"); -const { COMPOSE_NPM_PACKAGE, COMPOSE_NPM_VERSION } = require("../../config/constants"); - -async function scaffoldHardhat(projectName, templatePath, projectDir, options) { +import fs from "fs-extra"; +import path from "node:path"; +import { + copyTemplate, + readJson, + writeJson, +} from "../utils/fileManager.js"; +import { orderPackageJsonWithDepsBeforeDevDeps } from "../utils/packageOrderer.js"; +import { runCommand } from "../../utils/exec.js"; +import { logger } from "../../utils/logger.js"; +import { + COMPOSE_NPM_PACKAGE, + COMPOSE_NPM_VERSION, +} from "../../config/constants.js"; + +type ScaffoldOptions = { + installDeps?: boolean; +}; + +type ScaffoldResult = { + nextSteps: string[]; +}; + +export async function scaffoldHardhat( + projectName: string, + templatePath: string, + projectDir: string, + options: ScaffoldOptions +): Promise { await fs.ensureDir(projectDir); await copyTemplate(templatePath, projectDir); const shouldInstallDeps = Boolean(options.installDeps); const packageJsonPath = path.join(projectDir, "package.json"); - const packageJson = await readJson(packageJsonPath); + const packageJson = (await readJson(packageJsonPath)) as Record< + string, + unknown + > & { + name?: string; + type?: string; + scripts?: Record; + dependencies?: Record; + devDependencies?: Record; + }; packageJson.name = projectName; packageJson.type = "module"; @@ -27,7 +56,8 @@ async function scaffoldHardhat(projectName, templatePath, projectDir, options) { packageJson.dependencies = packageJson.dependencies || {}; packageJson.dependencies[COMPOSE_NPM_PACKAGE] = COMPOSE_NPM_VERSION; - const orderedPackageJson = orderPackageJsonWithDepsBeforeDevDeps(packageJson); + const orderedPackageJson = + orderPackageJsonWithDepsBeforeDevDeps(packageJson); await writeJson(packageJsonPath, orderedPackageJson); if (shouldInstallDeps) { @@ -43,8 +73,3 @@ async function scaffoldHardhat(projectName, templatePath, projectDir, options) { return { nextSteps }; } - -module.exports = { - scaffoldHardhat, -}; - diff --git a/cli/src/scaffold/scaffold.js b/cli/src/scaffold/scaffold.js deleted file mode 100644 index 2e75e0f5..00000000 --- a/cli/src/scaffold/scaffold.js +++ /dev/null @@ -1,49 +0,0 @@ -const fs = require("fs-extra"); -const { - assertTargetDoesNotExist, - assertDirectoryEmpty, - resolveProjectDir, - getProjectDisplayName, -} = require("./utils/fileManager"); -const { replaceTokensRecursively } = require("./utils/tokenReplace"); -const { scaffoldFoundry } = require("./frameworks/foundry"); -const { scaffoldHardhat } = require("./frameworks/hardhat"); - -async function scaffold({ projectName, templatePath, options }) { - const projectDir = resolveProjectDir(projectName); - if (projectName === ".") { - await assertDirectoryEmpty(projectDir); - } else { - await assertTargetDoesNotExist(projectDir); - } - - const displayName = getProjectDisplayName(projectName, projectDir); - - const templateExists = await fs.pathExists(templatePath); - if (!templateExists) { - throw new Error(`Template path does not exist: ${templatePath}`); - } - - let frameworkResult; - if (options.framework === "foundry") { - frameworkResult = await scaffoldFoundry(displayName, templatePath, projectDir, options); - } else if (options.framework === "hardhat") { - frameworkResult = await scaffoldHardhat(displayName, templatePath, projectDir, options); - } else { - throw new Error(`Unknown framework: ${options.framework}`); - } - - await replaceTokensRecursively(projectDir, { - "{{projectName}}": displayName, - }); - - return { - projectDir, - displayName, - nextSteps: frameworkResult?.nextSteps || [], - }; -} - -module.exports = { - scaffold, -}; diff --git a/cli/src/scaffold/scaffold.ts b/cli/src/scaffold/scaffold.ts new file mode 100644 index 00000000..c551dc6d --- /dev/null +++ b/cli/src/scaffold/scaffold.ts @@ -0,0 +1,77 @@ +import fs from "fs-extra"; +import { + assertTargetDoesNotExist, + assertDirectoryEmpty, + resolveProjectDir, + getProjectDisplayName, +} from "./utils/fileManager.js"; +import { replaceTokensRecursively } from "./utils/tokenReplace.js"; +import { scaffoldFoundry } from "./frameworks/foundry.js"; +import { scaffoldHardhat } from "./frameworks/hardhat.js"; + +type ScaffoldOptions = { + framework: string; + language?: string; + hardhatProjectType?: string; + installDeps?: boolean; +}; + +type ScaffoldParams = { + projectName: string; + templatePath: string; + options: ScaffoldOptions; +}; + +type ScaffoldResult = { + projectDir: string; + displayName: string; + nextSteps: string[]; +}; + +export async function scaffold( + params: ScaffoldParams +): Promise { + const { projectName, templatePath, options } = params; + const projectDir = resolveProjectDir(projectName); + if (projectName === ".") { + await assertDirectoryEmpty(projectDir); + } else { + await assertTargetDoesNotExist(projectDir); + } + + const displayName = getProjectDisplayName(projectName, projectDir); + + const templateExists = await fs.pathExists(templatePath); + if (!templateExists) { + throw new Error(`Template path does not exist: ${templatePath}`); + } + + let frameworkResult; + if (options.framework === "foundry") { + frameworkResult = await scaffoldFoundry( + displayName, + templatePath, + projectDir, + options + ); + } else if (options.framework === "hardhat") { + frameworkResult = await scaffoldHardhat( + displayName, + templatePath, + projectDir, + options + ); + } else { + throw new Error(`Unknown framework: ${options.framework}`); + } + + await replaceTokensRecursively(projectDir, { + "{{projectName}}": displayName, + }); + + return { + projectDir, + displayName, + nextSteps: frameworkResult?.nextSteps || [], + }; +} diff --git a/cli/src/scaffold/utils/fileManager.js b/cli/src/scaffold/utils/fileManager.js deleted file mode 100644 index cb90bced..00000000 --- a/cli/src/scaffold/utils/fileManager.js +++ /dev/null @@ -1,75 +0,0 @@ -const fs = require("fs-extra"); -const path = require("node:path"); - -async function assertTargetDoesNotExist(projectDir) { - const exists = await fs.pathExists(projectDir); - if (exists) { - throw new Error(`Target directory already exists: ${projectDir}`); - } -} - -async function copyTemplate(templateDir, projectDir) { - await fs.copy(templateDir, projectDir); -} - -async function readJson(filePath) { - return fs.readJson(filePath); -} - -async function writeJson(filePath, data) { - await fs.writeJson(filePath, data, { spaces: 2 }); -} - -async function appendLineIfMissing(filePath, line) { - const exists = await fs.pathExists(filePath); - if (!exists) { - await fs.outputFile(filePath, `${line}\n`); - return; - } - - const content = await fs.readFile(filePath, "utf8"); - if (!content.includes(line)) { - await fs.writeFile(filePath, `${content.trimEnd()}\n${line}\n`); - } -} - -async function assertDirectoryEmpty(projectDir) { - const entries = await fs.readdir(projectDir); - const ignoredEntries = [".git"]; - const nonIgnored = entries.filter((entry) => !ignoredEntries.includes(entry)); - if (nonIgnored.length > 0) { - throw new Error(`Target directory is not empty: ${projectDir}`); - } -} - -function resolveProjectDir(projectName) { - return path.join(process.cwd(), projectName); -} - -function getProjectDisplayName(projectName, projectDir) { - if (projectName === ".") { - return path.basename(projectDir); - } - return projectName; -} - -function getTemplateDisplayName(templatePath) { - const templatesRoot = path.join(__dirname, "..", "..", "templates"); - let templateName = path.relative(templatesRoot, templatePath).replace(/\\/g, "/"); - if (templateName.startsWith("..")) { - templateName = path.basename(templatePath); - } - return templateName; -} - -module.exports = { - assertTargetDoesNotExist, - assertDirectoryEmpty, - copyTemplate, - readJson, - writeJson, - appendLineIfMissing, - resolveProjectDir, - getProjectDisplayName, - getTemplateDisplayName, -}; diff --git a/cli/src/scaffold/utils/fileManager.ts b/cli/src/scaffold/utils/fileManager.ts new file mode 100644 index 00000000..5be3583d --- /dev/null +++ b/cli/src/scaffold/utils/fileManager.ts @@ -0,0 +1,87 @@ +import fs from "fs-extra"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export async function assertTargetDoesNotExist( + projectDir: string +): Promise { + const exists = await fs.pathExists(projectDir); + if (exists) { + throw new Error(`Target directory already exists: ${projectDir}`); + } +} + +export async function copyTemplate( + templateDir: string, + projectDir: string +): Promise { + await fs.copy(templateDir, projectDir); +} + +export async function readJson(filePath: string): Promise { + return fs.readJson(filePath); +} + +export async function writeJson( + filePath: string, + data: Record +): Promise { + await fs.writeJson(filePath, data, { spaces: 2 }); +} + +export async function appendLineIfMissing( + filePath: string, + line: string +): Promise { + const exists = await fs.pathExists(filePath); + if (!exists) { + await fs.outputFile(filePath, `${line}\n`); + return; + } + + const content: string = await fs.readFile(filePath, "utf8"); + if (!content.includes(line)) { + await fs.writeFile(filePath, `${content.trimEnd()}\n${line}\n`); + } +} + +export async function assertDirectoryEmpty( + projectDir: string +): Promise { + const entries = await fs.readdir(projectDir); + const ignoredEntries = [".git"]; + const nonIgnored = entries.filter( + (entry) => !ignoredEntries.includes(entry) + ); + if (nonIgnored.length > 0) { + throw new Error(`Target directory is not empty: ${projectDir}`); + } +} + +export function resolveProjectDir(projectName: string): string { + return path.join(process.cwd(), projectName); +} + +export function getProjectDisplayName( + projectName: string, + projectDir: string +): string { + if (projectName === ".") { + return path.basename(projectDir); + } + return projectName; +} + +export function getTemplateDisplayName(templatePath: string): string { + const templatesRoot = path.join(__dirname, "..", "..", "templates"); + let templateName = path + .relative(templatesRoot, templatePath) + .replace(/\\/g, "/"); + if (templateName.startsWith("..")) { + templateName = path.basename(templatePath); + } + return templateName; +} diff --git a/cli/src/scaffold/utils/packageOrderer.js b/cli/src/scaffold/utils/packageOrderer.ts similarity index 67% rename from cli/src/scaffold/utils/packageOrderer.js rename to cli/src/scaffold/utils/packageOrderer.ts index 26711440..4a225738 100644 --- a/cli/src/scaffold/utils/packageOrderer.js +++ b/cli/src/scaffold/utils/packageOrderer.ts @@ -1,5 +1,12 @@ -function orderPackageJsonWithDepsBeforeDevDeps(packageJson) { - const orderedPackageJson = {}; +type PackageJson = Record & { + dependencies?: Record; + devDependencies?: Record; +}; + +export function orderPackageJsonWithDepsBeforeDevDeps( + packageJson: PackageJson +): PackageJson { + const orderedPackageJson: Record = {}; const dependencies = packageJson.dependencies || {}; const devDependencies = packageJson.devDependencies || {}; let insertedDependencyBlocks = false; @@ -24,9 +31,5 @@ function orderPackageJsonWithDepsBeforeDevDeps(packageJson) { orderedPackageJson.devDependencies = devDependencies; } - return orderedPackageJson; + return orderedPackageJson as PackageJson; } - -module.exports = { - orderPackageJsonWithDepsBeforeDevDeps, -}; diff --git a/cli/src/scaffold/utils/templateLoader.js b/cli/src/scaffold/utils/templateLoader.js deleted file mode 100644 index 540c3309..00000000 --- a/cli/src/scaffold/utils/templateLoader.js +++ /dev/null @@ -1,51 +0,0 @@ -const path = require("node:path"); -const fs = require("fs-extra"); -const { TEMPLATE_REGISTRY_PATH } = require("../../config/constants"); -const { validateTemplatesConfig } = require("../../config/validateTemplatesConfig"); - -async function loadTemplateConfig() { - const config = await fs.readJson(TEMPLATE_REGISTRY_PATH); - validateTemplatesConfig(config); - return config; -} - -function pickVariant(config, options) { - const { template = config.defaultTemplateId, framework, language, projectType } = options; - - const templateEntry = config.templates.find((item) => item.id === template); - if (!templateEntry) { - throw new Error(`Template not found: ${template}`); - } - - const variant = templateEntry.variants.find((item) => { - if (framework && item.framework !== framework) { - return false; - } - if (item.framework === "hardhat" && language && item.language !== language) { - return false; - } - if (projectType && item.projectType && item.projectType !== projectType) { - return false; - } - if (!framework && item.id === config.defaultTemplateId) { - return true; - } - return framework ? true : false; - }); - - if (!variant) { - throw new Error(`No template variant for template=${template}, framework=${framework}, language=${language || "-"}`); - } - - return variant; -} - -function resolveTemplatePath(variant) { - return path.join(__dirname, "..", "..", variant.path); -} - -module.exports = { - loadTemplateConfig, - pickVariant, - resolveTemplatePath, -}; diff --git a/cli/src/scaffold/utils/templateLoader.ts b/cli/src/scaffold/utils/templateLoader.ts new file mode 100644 index 00000000..068639a3 --- /dev/null +++ b/cli/src/scaffold/utils/templateLoader.ts @@ -0,0 +1,87 @@ +import path from "node:path"; +import fs from "fs-extra"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; +import { TEMPLATE_REGISTRY_PATH } from "../../config/constants.js"; +import { validateTemplatesConfig } from "../../config/validateTemplatesConfig.js"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +type TemplateVariant = { + id: string; + framework: string; + path: string; + language?: string; + projectType?: string; +}; + +type Template = { + id: string; + name: string; + description?: string; + variants: TemplateVariant[]; +}; + +type TemplatesConfig = { + templates: Template[]; + defaultTemplateId: string; +}; + +type PickOptions = { + template?: string; + framework?: string; + language?: string; + projectType?: string; +}; + +export async function loadTemplateConfig(): Promise { + const config = await fs.readJson(TEMPLATE_REGISTRY_PATH); + validateTemplatesConfig(config); + return config as TemplatesConfig; +} + +export function pickVariant( + config: TemplatesConfig, + options: PickOptions +): TemplateVariant { + const { framework, language, projectType } = options; + const template = options.template || config.defaultTemplateId; + + const templateEntry = config.templates.find((item) => item.id === template); + if (!templateEntry) { + throw new Error(`Template not found: ${template}`); + } + + const variant = templateEntry.variants.find((item) => { + if (framework && item.framework !== framework) { + return false; + } + if ( + item.framework === "hardhat" && + language && + item.language !== language + ) { + return false; + } + if (projectType && item.projectType && item.projectType !== projectType) { + return false; + } + if (!framework && item.id === config.defaultTemplateId) { + return true; + } + return framework ? true : false; + }); + + if (!variant) { + throw new Error( + `No template variant for template=${template}, framework=${framework}, language=${language || "-"}` + ); + } + + return variant; +} + +export function resolveTemplatePath(variant: TemplateVariant): string { + return path.join(__dirname, "..", "..", variant.path); +} diff --git a/cli/src/scaffold/utils/tokenReplace.js b/cli/src/scaffold/utils/tokenReplace.ts similarity index 68% rename from cli/src/scaffold/utils/tokenReplace.js rename to cli/src/scaffold/utils/tokenReplace.ts index 1b39ad1e..fc018c8b 100644 --- a/cli/src/scaffold/utils/tokenReplace.js +++ b/cli/src/scaffold/utils/tokenReplace.ts @@ -1,8 +1,11 @@ -const fs = require("fs-extra"); -const path = require("node:path"); - -async function replaceTokensInFile(filePath, tokenMap) { - const content = await fs.readFile(filePath, "utf8"); +import fs from "fs-extra"; +import path from "node:path"; + +export async function replaceTokensInFile( + filePath: string, + tokenMap: Record +): Promise { + const content: string = await fs.readFile(filePath, "utf8"); let updated = content; Object.entries(tokenMap).forEach(([token, value]) => { @@ -14,7 +17,10 @@ async function replaceTokensInFile(filePath, tokenMap) { } } -async function replaceTokensRecursively(rootDir, tokenMap) { +export async function replaceTokensRecursively( + rootDir: string, + tokenMap: Record +): Promise { const entries = await fs.readdir(rootDir); await Promise.all( @@ -34,7 +40,3 @@ async function replaceTokensRecursively(rootDir, tokenMap) { }) ); } - -module.exports = { - replaceTokensRecursively, -}; diff --git a/cli/src/utils/composeAsciiHeader.js b/cli/src/utils/composeAsciiHeader.ts similarity index 86% rename from cli/src/utils/composeAsciiHeader.js rename to cli/src/utils/composeAsciiHeader.ts index de788527..3b51348f 100644 --- a/cli/src/utils/composeAsciiHeader.js +++ b/cli/src/utils/composeAsciiHeader.ts @@ -1,4 +1,4 @@ -const COMPOSE_HEADER = ` +export const COMPOSE_HEADER = ` _____ ____ __ __ _____ ____ _____ ______ _____ _ _____ / ____/ __ \\| \\/ | __ \\ / __ \\ / ____| ____| / ____| | |_ _| | | | | | | \\ / | |__) | | | | (___ | |__ | | | | | | @@ -6,8 +6,4 @@ const COMPOSE_HEADER = ` | |___| |__| | | | | | | |__| |____) | |____ | |____| |____ _| |_ \\_____\\____/|_| |_|_| \\____/|_____/|______| \\_____|______|_____| - ` - -module.exports = { - COMPOSE_HEADER, -}; \ No newline at end of file + `; diff --git a/cli/src/utils/errors.js b/cli/src/utils/errors.ts similarity index 64% rename from cli/src/utils/errors.js rename to cli/src/utils/errors.ts index d6cdbf7e..40f58453 100644 --- a/cli/src/utils/errors.js +++ b/cli/src/utils/errors.ts @@ -1,6 +1,6 @@ -const { logger } = require("./logger"); +import { logger } from "./logger.js"; -function normalizeError(error) { +function normalizeError(error: unknown): Error { if (error instanceof Error) { return error; } @@ -8,7 +8,7 @@ function normalizeError(error) { return new Error(String(error)); } -function exitWithError(error) { +export function exitWithError(error: unknown): void { const normalized = normalizeError(error); logger.error(normalized.message); @@ -18,8 +18,3 @@ function exitWithError(error) { process.exitCode = 1; } - -module.exports = { - normalizeError, - exitWithError, -}; diff --git a/cli/src/utils/exec.js b/cli/src/utils/exec.js deleted file mode 100644 index 9019a1ff..00000000 --- a/cli/src/utils/exec.js +++ /dev/null @@ -1,24 +0,0 @@ -const { spawn } = require("node:child_process"); - -function runCommand(command, args, options = {}) { - return new Promise((resolve, reject) => { - const child = spawn(command, args, { - stdio: "inherit", - ...options, - }); - - child.on("error", reject); - child.on("exit", (code) => { - if (code === 0) { - resolve(); - return; - } - - reject(new Error(`Command failed: ${command} ${args.join(" ")} (exit ${code})`)); - }); - }); -} - -module.exports = { - runCommand, -}; diff --git a/cli/src/utils/exec.ts b/cli/src/utils/exec.ts new file mode 100644 index 00000000..8e63a61f --- /dev/null +++ b/cli/src/utils/exec.ts @@ -0,0 +1,28 @@ +import { spawn, type SpawnOptions } from "node:child_process"; + +export function runCommand( + command: string, + args: string[], + options: SpawnOptions = {} +): Promise { + return new Promise((resolve, reject) => { + const child = spawn(command, args, { + stdio: "inherit", + ...options, + }); + + child.on("error", reject); + child.on("exit", (code) => { + if (code === 0) { + resolve(); + return; + } + + reject( + new Error( + `Command failed: ${command} ${args.join(" ")} (exit ${code})` + ) + ); + }); + }); +} diff --git a/cli/src/utils/helpText.js b/cli/src/utils/helpText.js deleted file mode 100644 index 9ce1b23b..00000000 --- a/cli/src/utils/helpText.js +++ /dev/null @@ -1,29 +0,0 @@ -const pkg = require("../../package.json"); -const { COMPOSE_DOCS_URL } = require("../config/constants"); - -const HELP_TEXT = ` -Compose CLI v${pkg.version} - -Scaffolds Diamond-based projects using the Compose Library - -Usage: - compose init [options] - compose list-templates - compose --version | -v - compose update - -Options: - --name - --template - --framework - --language - --install-deps | --no-install-deps - --yes - --help - -For more information about the Compose, see: ${COMPOSE_DOCS_URL} -`; - -module.exports = { - HELP_TEXT, -}; \ No newline at end of file diff --git a/cli/src/utils/helpText.ts b/cli/src/utils/helpText.ts new file mode 100644 index 00000000..7783d676 --- /dev/null +++ b/cli/src/utils/helpText.ts @@ -0,0 +1,32 @@ +import { createRequire } from "node:module"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const require = createRequire(import.meta.url); + +const pkg = require(resolve(__dirname, "..", "..", "package.json")); +import { COMPOSE_DOCS_URL } from "../config/constants.js"; + +export const HELP_TEXT = ` +Compose CLI v${pkg.version} + +Scaffolds Diamond-based projects using the Compose Library + +Usage: + compose init [options] + compose --version | -v + compose update + +Options: + --name + --template + --framework + --language + --install-deps | --no-install-deps + --yes + --help + +For more information about the Compose, see: ${COMPOSE_DOCS_URL} +`; diff --git a/cli/src/utils/logger.js b/cli/src/utils/logger.ts similarity index 53% rename from cli/src/utils/logger.js rename to cli/src/utils/logger.ts index 3d18bba6..f8a64af7 100644 --- a/cli/src/utils/logger.js +++ b/cli/src/utils/logger.ts @@ -1,26 +1,22 @@ -const pc = require("picocolors"); +import pc from "picocolors"; -const logger = { - info(message) { +export const logger = { + info(message: string) { console.log(pc.cyan(message)); }, - success(message) { + success(message: string) { console.log(pc.green(message)); }, - warn(message) { + warn(message: string) { console.warn(pc.yellow(message)); }, - brightYellow(message) { + brightYellow(message: string) { console.warn(pc.bold(pc.yellowBright(message))); }, - error(message) { + error(message: string) { console.error(pc.red(message)); }, - plain(message) { + plain(message: string) { console.log(message); }, }; - -module.exports = { - logger, -}; diff --git a/cli/src/utils/prompts/initUtils.js b/cli/src/utils/prompts/initUtils.js deleted file mode 100644 index 85ac0987..00000000 --- a/cli/src/utils/prompts/initUtils.js +++ /dev/null @@ -1,29 +0,0 @@ -const templateConfig = require("../../config/templates.json"); -const { assertDirectoryEmpty } = require("../../scaffold/utils/fileManager"); - -function getTemplateChoices() { - const list = templateConfig.templates || []; - if (list.length === 0) { - return [{ name: "Default", value: "default" }]; - } - return list.map((t) => ({ name: t.name, value: t.id })); -} - -async function validateProjectLocation(input) { - if (input !== ".") { - return true; - } - - try { - await assertDirectoryEmpty(process.cwd()); - return true; - } catch { - return 'Current directory must be empty (or only .git) when using ".".'; - } -} - -module.exports = { - getTemplateChoices, - validateProjectLocation, -}; - diff --git a/cli/src/utils/prompts/initUtils.ts b/cli/src/utils/prompts/initUtils.ts new file mode 100644 index 00000000..30cf70bc --- /dev/null +++ b/cli/src/utils/prompts/initUtils.ts @@ -0,0 +1,46 @@ +import { createRequire } from "node:module"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; +import { assertDirectoryEmpty } from "../../scaffold/utils/fileManager.js"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const require = createRequire(import.meta.url); + +const templateConfig = require(resolve( + __dirname, + "..", + "..", + "config", + "templates.json" +)) as { + templates: { id: string; name: string }[]; +}; + +type TemplateChoice = { + name: string; + value: string; +}; + +export function getTemplateChoices(): TemplateChoice[] { + const list = templateConfig.templates || []; + if (list.length === 0) { + return [{ name: "Default", value: "default" }]; + } + return list.map((t) => ({ name: t.name, value: t.id })); +} + +export async function validateProjectLocation( + input: string +): Promise { + if (input !== ".") { + return true; + } + + try { + await assertDirectoryEmpty(process.cwd()); + return true; + } catch { + return 'Current directory must be empty (or only .git) when using ".".'; + } +} diff --git a/cli/test/integration/cliEntry.test.js b/cli/test/integration/cliEntry.test.js deleted file mode 100644 index 6d2116ee..00000000 --- a/cli/test/integration/cliEntry.test.js +++ /dev/null @@ -1,35 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const { spawnSync } = require("node:child_process"); - -const cliPath = path.join(__dirname, "..", "..", "index.js"); - -function runCli(args) { - return spawnSync(process.execPath, [cliPath, ...args], { - encoding: "utf8", - }); -} - -test("compose --version prints version and exits cleanly", () => { - const result = runCli(["--version"]); - const packageJson = require("../../package.json"); - - assert.equal(result.status, 0); - assert.equal(result.stdout.trim(), packageJson.version); -}); - -test("compose --help prints usage text", () => { - const result = runCli(["--help"]); - - assert.equal(result.status, 0); - assert.equal(result.stdout.includes("Usage:"), true); - assert.equal(result.stdout.includes("compose init [options]"), true); -}); - -test("compose unknown command exits with error", () => { - const result = runCli(["does-not-exist"]); - - assert.equal(result.status, 1); - assert.equal(result.stderr.includes("Unknown command"), true); -}); diff --git a/cli/test/integration/cliEntry.test.ts b/cli/test/integration/cliEntry.test.ts new file mode 100644 index 00000000..7e69356c --- /dev/null +++ b/cli/test/integration/cliEntry.test.ts @@ -0,0 +1,43 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; +import { createRequire } from "node:module"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const require = createRequire(import.meta.url); + +const cliPath = resolve(__dirname, "..", "..", "bin", "compose.ts"); +const pkg = require(resolve(__dirname, "..", "..", "package.json")) as { + version: string; +}; + +function runCli(args: string[]) { + return spawnSync("npx", ["tsx", cliPath, ...args], { + encoding: "utf8", + }); +} + +test("compose --version prints version and exits cleanly", () => { + const result = runCli(["--version"]); + + assert.equal(result.status, 0); + assert.equal(result.stdout.trim(), pkg.version); +}); + +test("compose --help prints usage text", () => { + const result = runCli(["--help"]); + + assert.equal(result.status, 0); + assert.equal(result.stdout.includes("Usage:"), true); + assert.equal(result.stdout.includes("init"), true); +}); + +test("compose unknown command exits with error", () => { + const result = runCli(["does-not-exist"]); + + assert.equal(result.status, 1); + assert.equal(result.stderr.length > 0 || result.stdout.includes("error"), true); +}); diff --git a/cli/test/integration/scaffoldVariants.test.js b/cli/test/integration/scaffoldVariants.test.ts similarity index 61% rename from cli/test/integration/scaffoldVariants.test.js rename to cli/test/integration/scaffoldVariants.test.ts index eaf1ac53..02bafddf 100644 --- a/cli/test/integration/scaffoldVariants.test.js +++ b/cli/test/integration/scaffoldVariants.test.ts @@ -1,17 +1,22 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const os = require("node:os"); -const fs = require("fs-extra"); -const { +import test from "node:test"; +import assert from "node:assert/strict"; +import path from "node:path"; +import os from "node:os"; +import fs from "fs-extra"; +import { loadTemplateConfig, pickVariant, resolveTemplatePath, -} = require("../../src/scaffold/utils/templateLoader"); -const { scaffold } = require("../../src/scaffold/scaffold"); - -async function scaffoldWithVariant(variant, options = {}) { - const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-it-")); +} from "../../src/scaffold/utils/templateLoader.js"; +import { scaffold } from "../../src/scaffold/scaffold.js"; + +async function scaffoldWithVariant( + variant: ReturnType, + options: { projectName?: string } = {} +) { + const tempRoot = await fs.mkdtemp( + path.join(os.tmpdir(), "compose-cli-it-") + ); const originalCwd = process.cwd(); process.chdir(tempRoot); try { @@ -26,7 +31,11 @@ async function scaffoldWithVariant(variant, options = {}) { installDeps: false, }, }); - return { tempRoot, projectDir: result.projectDir, nextSteps: result.nextSteps }; + return { + tempRoot, + projectDir: result.projectDir, + nextSteps: result.nextSteps, + }; } finally { process.chdir(originalCwd); } @@ -44,9 +53,14 @@ test("scaffolds hardhat minimal variant", async () => { const { projectDir, nextSteps } = await scaffoldWithVariant(variant, { projectName: "hardhat-minimal-app", }); - const packageJson = await fs.readJson(path.join(projectDir, "package.json")); + const packageJson: { name?: string } = await fs.readJson( + path.join(projectDir, "package.json") + ); - assert.equal(await fs.pathExists(path.join(projectDir, "hardhat.config.ts")), true); + assert.equal( + await fs.pathExists(path.join(projectDir, "hardhat.config.ts")), + true + ); assert.equal(packageJson.name, "hardhat-minimal-app"); assert.equal(nextSteps.includes("npm install"), true); }); @@ -60,10 +74,18 @@ test("scaffolds hardhat mocha-ethers variant", async () => { projectType: "mocha-ethers", }); - const { projectDir } = await scaffoldWithVariant(variant, { projectName: "hardhat-mocha-app" }); - const readme = await fs.readFile(path.join(projectDir, "README.md"), "utf8"); + const { projectDir } = await scaffoldWithVariant(variant, { + projectName: "hardhat-mocha-app", + }); + const readme: string = await fs.readFile( + path.join(projectDir, "README.md"), + "utf8" + ); - assert.equal(await fs.pathExists(path.join(projectDir, "test", "Counter.ts")), true); + assert.equal( + await fs.pathExists(path.join(projectDir, "test", "Counter.ts")), + true + ); assert.equal(readme.includes("{{projectName}}"), false); assert.equal(readme.includes("hardhat-mocha-app"), true); }); @@ -80,11 +102,15 @@ test("scaffolds hardhat node-runner-viem variant", async () => { const { projectDir } = await scaffoldWithVariant(variant, { projectName: "hardhat-viem-app", }); - const packageJson = await fs.readJson(path.join(projectDir, "package.json")); + const packageJson: { dependencies?: Record } = + await fs.readJson(path.join(projectDir, "package.json")); - assert.equal(await fs.pathExists(path.join(projectDir, "test", "Counter.ts")), true); assert.equal( - packageJson.dependencies["@perfect-abstractions/compose"], + await fs.pathExists(path.join(projectDir, "test", "Counter.ts")), + true + ); + assert.equal( + packageJson.dependencies?.["@perfect-abstractions/compose"], "latest" ); }); @@ -98,7 +124,9 @@ test("scaffolds into current directory when projectName is dot and directory is projectType: "minimal", }); - const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-it-dot-")); + const tempRoot = await fs.mkdtemp( + path.join(os.tmpdir(), "compose-cli-it-dot-") + ); const originalCwd = process.cwd(); process.chdir(tempRoot); @@ -114,7 +142,9 @@ test("scaffolds into current directory when projectName is dot and directory is }, }); - const packageJson = await fs.readJson(path.join(result.projectDir, "package.json")); + const packageJson: { name?: string } = await fs.readJson( + path.join(result.projectDir, "package.json") + ); assert.equal(result.projectDir, tempRoot); assert.equal(packageJson.name, path.basename(tempRoot)); } finally { @@ -127,7 +157,11 @@ test("scaffold throws for unknown framework", async () => { () => scaffold({ projectName: "demo", - templatePath: resolveTemplatePath({ path: "templates/default/foundry" }), + templatePath: resolveTemplatePath({ + id: "test", + framework: "foundry", + path: "templates/default/foundry", + }), options: { framework: "unknown", installDeps: false }, }), /Unknown framework/ @@ -139,8 +173,15 @@ test("scaffold throws when template path is missing", async () => { () => scaffold({ projectName: "demo", - templatePath: path.join(process.cwd(), "this-template-does-not-exist"), - options: { framework: "hardhat", language: "typescript", installDeps: false }, + templatePath: path.join( + process.cwd(), + "this-template-does-not-exist" + ), + options: { + framework: "hardhat", + language: "typescript", + installDeps: false, + }, }), /Template path does not exist/ ); diff --git a/cli/test/unit/errors.test.js b/cli/test/unit/errors.test.ts similarity index 57% rename from cli/test/unit/errors.test.js rename to cli/test/unit/errors.test.ts index c3d4250a..7abbc44b 100644 --- a/cli/test/unit/errors.test.js +++ b/cli/test/unit/errors.test.ts @@ -1,28 +1,17 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { normalizeError, exitWithError } = require("../../src/utils/errors"); -const { logger } = require("../../src/utils/logger"); - -test("normalizeError returns original Error instance", () => { - const error = new Error("boom"); - assert.equal(normalizeError(error), error); -}); - -test("normalizeError wraps non-error values", () => { - const normalized = normalizeError("boom"); - assert.equal(normalized instanceof Error, true); - assert.equal(normalized.message, "boom"); -}); +import test from "node:test"; +import assert from "node:assert/strict"; +import { exitWithError } from "../../src/utils/errors.js"; +import { logger } from "../../src/utils/logger.js"; test("exitWithError logs error and sets process.exitCode", () => { - const calls = []; + const calls: [string, string][] = []; const originalError = logger.error; const originalPlain = logger.plain; const originalExitCode = process.exitCode; - let exitCodeAfterCall; + let exitCodeAfterCall: number | undefined; - logger.error = (message) => calls.push(["error", message]); - logger.plain = (message) => calls.push(["plain", message]); + logger.error = (message: string) => calls.push(["error", message]); + logger.plain = (message: string) => calls.push(["plain", message]); delete process.env.DEBUG; process.exitCode = 0; @@ -40,15 +29,15 @@ test("exitWithError logs error and sets process.exitCode", () => { }); test("exitWithError logs stack trace when DEBUG=1", () => { - const calls = []; + const calls: [string, string][] = []; const originalError = logger.error; const originalPlain = logger.plain; const originalDebug = process.env.DEBUG; const originalExitCode = process.exitCode; - let exitCodeAfterCall; + let exitCodeAfterCall: number | undefined; - logger.error = (message) => calls.push(["error", message]); - logger.plain = (message) => calls.push(["plain", message]); + logger.error = (message: string) => calls.push(["error", message]); + logger.plain = (message: string) => calls.push(["plain", message]); process.env.DEBUG = "1"; process.exitCode = 0; @@ -66,6 +55,6 @@ test("exitWithError logs stack trace when DEBUG=1", () => { assert.equal(calls[0][1], "debug-failure"); assert.equal(calls[1][0], "plain"); assert.equal(typeof calls[1][1], "string"); - assert.equal(calls[1][1].includes("debug-failure"), true); + assert.equal((calls[1][1] as string).includes("debug-failure"), true); assert.equal(exitCodeAfterCall, 1); }); diff --git a/cli/test/unit/fileManager.test.js b/cli/test/unit/fileManager.test.ts similarity index 67% rename from cli/test/unit/fileManager.test.js rename to cli/test/unit/fileManager.test.ts index 37f29fcd..f99205c5 100644 --- a/cli/test/unit/fileManager.test.js +++ b/cli/test/unit/fileManager.test.ts @@ -1,36 +1,52 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const os = require("node:os"); -const fs = require("fs-extra"); -const { +import test from "node:test"; +import assert from "node:assert/strict"; +import path from "node:path"; +import os from "node:os"; +import fs from "fs-extra"; +import { assertTargetDoesNotExist, appendLineIfMissing, assertDirectoryEmpty, getProjectDisplayName, getTemplateDisplayName, -} = require("../../src/scaffold/utils/fileManager"); +} from "../../src/scaffold/utils/fileManager.js"; test("assertTargetDoesNotExist throws when path already exists", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-fm-")); - await assert.rejects(() => assertTargetDoesNotExist(tempDir), /Target directory already exists/); + const tempDir = await fs.mkdtemp( + path.join(os.tmpdir(), "compose-cli-fm-") + ); + await assert.rejects( + () => assertTargetDoesNotExist(tempDir), + /Target directory already exists/ + ); }); test("appendLineIfMissing creates file and avoids duplicate lines", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-fm-")); + const tempDir = await fs.mkdtemp( + path.join(os.tmpdir(), "compose-cli-fm-") + ); const filePath = path.join(tempDir, ".gitignore"); await appendLineIfMissing(filePath, "node_modules"); await appendLineIfMissing(filePath, "node_modules"); await appendLineIfMissing(filePath, "dist"); - const content = await fs.readFile(filePath, "utf8"); + const content: string = await fs.readFile(filePath, "utf8"); assert.equal(content, "node_modules\ndist\n"); }); test("getTemplateDisplayName returns relative template path when inside templates root", () => { - const templatePath = path.join(process.cwd(), "src", "templates", "default", "foundry"); - assert.equal(getTemplateDisplayName(templatePath), "default/foundry"); + const templatePath = path.join( + process.cwd(), + "src", + "templates", + "default", + "foundry" + ); + assert.equal( + getTemplateDisplayName(templatePath), + "default/foundry" + ); }); test("getTemplateDisplayName falls back to basename for external paths", () => { @@ -39,17 +55,16 @@ test("getTemplateDisplayName falls back to basename for external paths", () => { }); test("assertDirectoryEmpty allows only .git in directory", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-fm-empty-")); + const tempDir = await fs.mkdtemp( + path.join(os.tmpdir(), "compose-cli-fm-empty-") + ); - // Empty directory is allowed await assert.doesNotReject(() => assertDirectoryEmpty(tempDir)); - // Directory with only .git is allowed const gitDir = path.join(tempDir, ".git"); await fs.mkdir(gitDir); await assert.doesNotReject(() => assertDirectoryEmpty(tempDir)); - // Any additional entry should cause a failure const readmePath = path.join(tempDir, "README.md"); await fs.writeFile(readmePath, "# demo\n"); await assert.rejects( diff --git a/cli/test/unit/initOptions.test.js b/cli/test/unit/initOptions.test.ts similarity index 84% rename from cli/test/unit/initOptions.test.js rename to cli/test/unit/initOptions.test.ts index ae338ee4..738a7df3 100644 --- a/cli/test/unit/initOptions.test.js +++ b/cli/test/unit/initOptions.test.ts @@ -1,6 +1,6 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { normalizeInitOptions } = require("../../src/commands/init"); +import test from "node:test"; +import assert from "node:assert/strict"; +import { normalizeInitOptions } from "../../src/commands/init.js"; test("normalizeInitOptions sets defaults", () => { const options = normalizeInitOptions({}); diff --git a/cli/test/unit/initPrompts.test.js b/cli/test/unit/initPrompts.test.ts similarity index 63% rename from cli/test/unit/initPrompts.test.js rename to cli/test/unit/initPrompts.test.ts index f9a8486e..eb75f883 100644 --- a/cli/test/unit/initPrompts.test.js +++ b/cli/test/unit/initPrompts.test.ts @@ -1,11 +1,10 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const os = require("node:os"); -const fs = require("fs-extra"); - -const { assertDirectoryEmpty } = require("../../src/scaffold/utils/fileManager"); -const { validateProjectLocation } = require("../../src/utils/prompts/initUtils"); +import test from "node:test"; +import assert from "node:assert/strict"; +import path from "node:path"; +import os from "node:os"; +import fs from "fs-extra"; +import { assertDirectoryEmpty } from "../../src/scaffold/utils/fileManager.js"; +import { validateProjectLocation } from "../../src/utils/prompts/initUtils.js"; test("validateProjectLocation returns true for non-dot names", async () => { const result = await validateProjectLocation("my-app"); @@ -13,12 +12,13 @@ test("validateProjectLocation returns true for non-dot names", async () => { }); test("validateProjectLocation accepts dot in logically empty directory", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-init-")); + const tempDir = await fs.mkdtemp( + path.join(os.tmpdir(), "compose-cli-init-") + ); const originalCwd = process.cwd(); process.chdir(tempDir); try { - // Ensure our invariant helper agrees this directory is acceptable await assertDirectoryEmpty(process.cwd()); const result = await validateProjectLocation("."); @@ -29,7 +29,9 @@ test("validateProjectLocation accepts dot in logically empty directory", async ( }); test("validateProjectLocation rejects dot in non-empty directory", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-init-")); + const tempDir = await fs.mkdtemp( + path.join(os.tmpdir(), "compose-cli-init-") + ); const originalCwd = process.cwd(); process.chdir(tempDir); @@ -46,4 +48,3 @@ test("validateProjectLocation rejects dot in non-empty directory", async () => { process.chdir(originalCwd); } }); - diff --git a/cli/test/unit/packageOrderer.test.js b/cli/test/unit/packageOrderer.test.ts similarity index 62% rename from cli/test/unit/packageOrderer.test.js rename to cli/test/unit/packageOrderer.test.ts index 90d996f7..b2a2d573 100644 --- a/cli/test/unit/packageOrderer.test.js +++ b/cli/test/unit/packageOrderer.test.ts @@ -1,6 +1,6 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { orderPackageJsonWithDepsBeforeDevDeps } = require("../../src/scaffold/utils/packageOrderer"); +import test from "node:test"; +import assert from "node:assert/strict"; +import { orderPackageJsonWithDepsBeforeDevDeps } from "../../src/scaffold/utils/packageOrderer.js"; test("places dependencies before devDependencies", () => { const input = { @@ -22,9 +22,15 @@ test("places dependencies before devDependencies", () => { }); test("adds missing dependency blocks when absent", () => { - const ordered = orderPackageJsonWithDepsBeforeDevDeps({ name: "demo" }); + const ordered = orderPackageJsonWithDepsBeforeDevDeps({ + name: "demo", + }); - assert.deepEqual(Object.keys(ordered), ["name", "dependencies", "devDependencies"]); + assert.deepEqual(Object.keys(ordered), [ + "name", + "dependencies", + "devDependencies", + ]); assert.deepEqual(ordered.dependencies, {}); assert.deepEqual(ordered.devDependencies, {}); }); diff --git a/cli/test/unit/templateLoader.test.js b/cli/test/unit/templateLoader.test.ts similarity index 83% rename from cli/test/unit/templateLoader.test.js rename to cli/test/unit/templateLoader.test.ts index 4ac52aab..a3cbc6d6 100644 --- a/cli/test/unit/templateLoader.test.js +++ b/cli/test/unit/templateLoader.test.ts @@ -1,10 +1,10 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { +import test from "node:test"; +import assert from "node:assert/strict"; +import { loadTemplateConfig, pickVariant, resolveTemplatePath, -} = require("../../src/scaffold/utils/templateLoader"); +} from "../../src/scaffold/utils/templateLoader.js"; test("pickVariant returns foundry variant", async () => { const config = await loadTemplateConfig(); @@ -54,6 +54,10 @@ test("pickVariant throws when no variant matches", async () => { }); test("resolveTemplatePath returns an absolute path in src", () => { - const resolved = resolveTemplatePath({ path: "templates/default/foundry" }); + const resolved = resolveTemplatePath({ + id: "test", + framework: "foundry", + path: "templates/default/foundry", + }); assert.equal(resolved.includes("/src/templates/default/foundry"), true); }); diff --git a/cli/test/unit/templateSnapshot.test.js b/cli/test/unit/templateSnapshot.test.js deleted file mode 100644 index 483d3193..00000000 --- a/cli/test/unit/templateSnapshot.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const fs = require("fs-extra"); -const path = require("node:path"); -const { loadTemplateConfig } = require("../../src/scaffold/utils/templateLoader"); - -test("template variants match snapshot", async () => { - const snapshotPath = path.join(__dirname, "..", "fixtures", "template-variants.snapshot.json"); - const snapshot = await fs.readJson(snapshotPath); - const config = await loadTemplateConfig(); - - const actual = {}; - config.templates.forEach((template) => { - actual[template.id] = template.variants.map((variant) => variant.id); - }); - - assert.deepEqual(actual, snapshot); -}); diff --git a/cli/test/unit/templateSnapshot.test.ts b/cli/test/unit/templateSnapshot.test.ts new file mode 100644 index 00000000..a6d52233 --- /dev/null +++ b/cli/test/unit/templateSnapshot.test.ts @@ -0,0 +1,30 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import fs from "fs-extra"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; +import { loadTemplateConfig } from "../../src/scaffold/utils/templateLoader.js"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +test("template variants match snapshot", async () => { + const snapshotPath = path.join( + __dirname, + "..", + "fixtures", + "template-variants.snapshot.json" + ); + const snapshot: Record = await fs.readJson( + snapshotPath + ); + const config = await loadTemplateConfig(); + + const actual: Record = {}; + config.templates.forEach((template) => { + actual[template.id] = template.variants.map((variant) => variant.id); + }); + + assert.deepEqual(actual, snapshot); +}); diff --git a/cli/test/unit/tokenReplace.test.js b/cli/test/unit/tokenReplace.test.ts similarity index 50% rename from cli/test/unit/tokenReplace.test.js rename to cli/test/unit/tokenReplace.test.ts index 1645af96..c7f52294 100644 --- a/cli/test/unit/tokenReplace.test.js +++ b/cli/test/unit/tokenReplace.test.ts @@ -1,12 +1,14 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const os = require("node:os"); -const fs = require("fs-extra"); -const { replaceTokensRecursively } = require("../../src/scaffold/utils/tokenReplace"); +import test from "node:test"; +import assert from "node:assert/strict"; +import path from "node:path"; +import os from "node:os"; +import fs from "fs-extra"; +import { replaceTokensRecursively } from "../../src/scaffold/utils/tokenReplace.js"; test("replaceTokensRecursively updates supported text files recursively", async () => { - const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-tr-")); + const rootDir = await fs.mkdtemp( + path.join(os.tmpdir(), "compose-cli-tr-") + ); const nestedDir = path.join(rootDir, "nested"); await fs.ensureDir(nestedDir); @@ -20,7 +22,16 @@ test("replaceTokensRecursively updates supported text files recursively", async await replaceTokensRecursively(rootDir, { "{{projectName}}": "demo-app" }); - assert.equal(await fs.readFile(readmePath, "utf8"), "Project demo-app"); - assert.equal(await fs.readFile(jsonPath, "utf8"), '{"name":"demo-app"}'); - assert.equal(await fs.readFile(pngPath, "utf8"), "binary-{{projectName}}"); + assert.equal( + await fs.readFile(readmePath, "utf8"), + "Project demo-app" + ); + assert.equal( + await fs.readFile(jsonPath, "utf8"), + '{"name":"demo-app"}' + ); + assert.equal( + await fs.readFile(pngPath, "utf8"), + "binary-{{projectName}}" + ); }); diff --git a/cli/test/unit/validateTemplatesConfig.test.js b/cli/test/unit/validateTemplatesConfig.test.js deleted file mode 100644 index 9808ad2a..00000000 --- a/cli/test/unit/validateTemplatesConfig.test.js +++ /dev/null @@ -1,19 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const templatesConfig = require("../../src/config/templates.json"); -const { validateTemplatesConfig } = require("../../src/config/validateTemplatesConfig"); - -test("validateTemplatesConfig accepts current registry", () => { - assert.equal(validateTemplatesConfig(templatesConfig), true); -}); - -test("validateTemplatesConfig rejects missing variants", () => { - assert.throws( - () => - validateTemplatesConfig({ - templates: [{ id: "default", name: "Default", variants: [] }], - defaultTemplateId: "default", - }), - /variants must be a non-empty array/ - ); -}); diff --git a/cli/test/unit/validateTemplatesConfig.test.ts b/cli/test/unit/validateTemplatesConfig.test.ts new file mode 100644 index 00000000..5fdd6e3d --- /dev/null +++ b/cli/test/unit/validateTemplatesConfig.test.ts @@ -0,0 +1,30 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { validateTemplatesConfig } from "../../src/config/validateTemplatesConfig.js"; + +test("validateTemplatesConfig accepts current registry", () => { + assert.equal(validateTemplatesConfig({ + templates: [ + { + id: "default", + name: "Counter", + description: "Simple diamond with a counter facet", + variants: [ + { id: "default-foundry", framework: "foundry", path: "templates/default/foundry" }, + ], + }, + ], + defaultTemplateId: "default", + }), true); +}); + +test("validateTemplatesConfig rejects missing variants", () => { + assert.throws( + () => + validateTemplatesConfig({ + templates: [{ id: "default", name: "Default", variants: [] }], + defaultTemplateId: "default", + }), + /variants must be a non-empty array/ + ); +}); diff --git a/cli/test/unit/versionCommand.test.js b/cli/test/unit/versionCommand.test.js deleted file mode 100644 index 629545e6..00000000 --- a/cli/test/unit/versionCommand.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { runVersionCommand } = require("../../src/commands/version"); -const { logger } = require("../../src/utils/logger"); - -test("runVersionCommand prints version string", () => { - const calls = []; - const originalPlain = logger.plain; - logger.plain = (message) => calls.push(message); - - try { - runVersionCommand("1.2.3"); - } finally { - logger.plain = originalPlain; - } - - assert.deepEqual(calls, ["1.2.3"]); -}); diff --git a/cli/test/unit/versionCommand.test.ts b/cli/test/unit/versionCommand.test.ts new file mode 100644 index 00000000..3fddf37d --- /dev/null +++ b/cli/test/unit/versionCommand.test.ts @@ -0,0 +1,18 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { runVersionCommand } from "../../src/commands/version.js"; +import { logger } from "../../src/utils/logger.js"; + +test("runVersionCommand prints version string", () => { + const calls: string[] = []; + const originalPlain = logger.plain; + logger.plain = (message: string) => calls.push(message); + + try { + runVersionCommand("1.2.3"); + } finally { + logger.plain = originalPlain; + } + + assert.deepEqual(calls, ["1.2.3"]); +}); diff --git a/cli/tsconfig.json b/cli/tsconfig.json new file mode 100644 index 00000000..715a6fca --- /dev/null +++ b/cli/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "rootDir": ".", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "verbatimModuleSyntax": false + }, + "include": [ + "bin/**/*.ts", + "src/**/*.ts", + "index.ts" + ], + "exclude": [ + "node_modules", + "dist", + "test", + "src/templates" + ] +} diff --git a/package-lock.json b/package-lock.json index a84f60a2..3aa9b2f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,13 @@ "cli", "website" ], + "dependencies": { + "commander": "^13.1.0" + }, "devDependencies": { - "@changesets/cli": "^2.30.0" + "@changesets/cli": "^2.30.0", + "@types/fs-extra": "^11.0.4", + "typescript-eslint": "^8.60.0" } }, "cli": { @@ -22,9 +27,9 @@ "version": "0.0.5", "license": "MIT", "dependencies": { + "commander": "^13.1.0", "fs-extra": "^11.3.3", "inquirer": "^13.3.0", - "minimist": "^1.2.8", "picocolors": "^1.1.1" }, "bin": { @@ -46,7 +51,9 @@ "forge-std": "github:foundry-rs/forge-std#v1.9.4", "hardhat": "^3.1.10", "mocha": "^11.7.5", + "tsx": "^4.19.0", "typescript": "~5.8.0", + "typescript-eslint": "^8.30.0", "viem": "^2.47.0" }, "engines": { @@ -104,77 +111,6 @@ "node": ">=18" } }, - "cli/node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "cli/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "cli/node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "cli/node_modules/@eslint/config-array": { - "version": "0.23.3", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^3.0.3", - "debug": "^4.3.1", - "minimatch": "^10.2.4" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "cli/node_modules/@eslint/config-helpers": { - "version": "0.5.3", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.1.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "cli/node_modules/@eslint/core": { - "version": "1.1.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, "cli/node_modules/@eslint/js": { "version": "10.0.1", "dev": true, @@ -194,26 +130,6 @@ } } }, - "cli/node_modules/@eslint/object-schema": { - "version": "3.0.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "cli/node_modules/@eslint/plugin-kit": { - "version": "0.6.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.1.1", - "levn": "^0.4.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, "cli/node_modules/@ethersproject/abi": { "version": "5.8.0", "dev": true, @@ -596,50 +512,6 @@ "node": ">=14" } }, - "cli/node_modules/@humanfs/core": { - "version": "0.19.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "cli/node_modules/@humanfs/node": { - "version": "0.16.7", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "cli/node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "cli/node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, "cli/node_modules/@inquirer/ansi": { "version": "2.0.3", "license": "MIT", @@ -1677,21 +1549,6 @@ "dev": true, "license": "MIT" }, - "cli/node_modules/@types/esrecurse": { - "version": "4.3.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/@types/estree": { - "version": "1.0.8", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/@types/json-schema": { - "version": "7.0.15", - "dev": true, - "license": "MIT" - }, "cli/node_modules/@types/mocha": { "version": "10.0.10", "dev": true, @@ -1731,26 +1588,6 @@ } } }, - "cli/node_modules/acorn": { - "version": "8.16.0", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "cli/node_modules/acorn-jsx": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, "cli/node_modules/adm-zip": { "version": "0.4.16", "dev": true, @@ -1764,21 +1601,6 @@ "dev": true, "license": "MIT" }, - "cli/node_modules/ajv": { - "version": "6.14.0", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "cli/node_modules/ansi-styles": { "version": "5.2.0", "dev": true, @@ -1806,30 +1628,11 @@ "node": ">=12" } }, - "cli/node_modules/balanced-match": { - "version": "4.0.4", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, "cli/node_modules/bn.js": { "version": "5.2.3", "dev": true, "license": "MIT" }, - "cli/node_modules/brace-expansion": { - "version": "5.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, "cli/node_modules/brorand": { "version": "1.1.0", "dev": true, @@ -2109,22 +1912,6 @@ "dev": true, "license": "MIT" }, - "cli/node_modules/debug": { - "version": "4.4.3", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "cli/node_modules/decamelize": { "version": "4.0.0", "dev": true, @@ -2152,11 +1939,6 @@ "node": ">=4.0.0" } }, - "cli/node_modules/deep-is": { - "version": "0.1.4", - "dev": true, - "license": "MIT" - }, "cli/node_modules/diff": { "version": "7.0.0", "dev": true, @@ -2258,174 +2040,26 @@ "node": ">=6" } }, - "cli/node_modules/escape-string-regexp": { - "version": "4.0.0", + "cli/node_modules/ethereum-cryptography": { + "version": "2.2.1", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" } }, - "cli/node_modules/eslint": { - "version": "10.1.0", + "cli/node_modules/ethereum-cryptography/node_modules/@noble/hashes": { + "version": "1.4.0", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.3", - "@eslint/config-helpers": "^0.5.3", - "@eslint/core": "^1.1.1", - "@eslint/plugin-kit": "^0.6.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.2", - "eslint-visitor-keys": "^5.0.1", - "espree": "^11.2.0", - "esquery": "^1.7.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">= 16" }, "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "cli/node_modules/eslint-scope": { - "version": "9.1.2", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "cli/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "cli/node_modules/espree": { - "version": "11.2.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.16.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "cli/node_modules/esquery": { - "version": "1.7.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "cli/node_modules/esrecurse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "cli/node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "cli/node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "cli/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "cli/node_modules/ethereum-cryptography/node_modules/@noble/hashes": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "url": "https://paulmillr.com/funding/" } }, "cli/node_modules/ethers": { @@ -2501,11 +2135,6 @@ "dev": true, "license": "MIT" }, - "cli/node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "license": "MIT" - }, "cli/node_modules/fast-equals": { "version": "5.4.0", "dev": true, @@ -2514,16 +2143,6 @@ "node": ">=6.0.0" } }, - "cli/node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, "cli/node_modules/fast-string-truncated-width": { "version": "3.0.3", "license": "MIT" @@ -2542,17 +2161,6 @@ "fast-string-width": "^3.0.2" } }, - "cli/node_modules/file-entry-cache": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, "cli/node_modules/find-replace": { "version": "3.0.0", "dev": true, @@ -2587,23 +2195,6 @@ "flat": "cli.js" } }, - "cli/node_modules/flat-cache": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "cli/node_modules/flatted": { - "version": "3.3.4", - "dev": true, - "license": "ISC" - }, "cli/node_modules/foreground-child": { "version": "3.3.1", "dev": true, @@ -2674,17 +2265,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "cli/node_modules/glob-parent": { - "version": "6.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "cli/node_modules/glob/node_modules/balanced-match": { "version": "1.0.2", "dev": true, @@ -2807,14 +2387,6 @@ "url": "https://opencollective.com/immer" } }, - "cli/node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, "cli/node_modules/inflight": { "version": "1.0.6", "dev": true, @@ -2983,21 +2555,6 @@ "dev": true, "license": "MIT" }, - "cli/node_modules/json-buffer": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, "cli/node_modules/json-stream-stringify": { "version": "3.1.6", "dev": true, @@ -3032,14 +2589,6 @@ "graceful-fs": "^4.1.6" } }, - "cli/node_modules/keyv": { - "version": "4.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, "cli/node_modules/kleur": { "version": "3.0.3", "dev": true, @@ -3048,18 +2597,6 @@ "node": ">=6" } }, - "cli/node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "cli/node_modules/locate-path": { "version": "6.0.0", "dev": true, @@ -3213,22 +2750,9 @@ "dev": true, "license": "MIT" }, - "cli/node_modules/minimatch": { - "version": "10.2.4", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "cli/node_modules/minimist": { "version": "1.2.8", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3316,11 +2840,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "cli/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "license": "MIT" - }, "cli/node_modules/mute-stream": { "version": "3.0.0", "license": "ISC", @@ -3328,11 +2847,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "cli/node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, "cli/node_modules/ndjson": { "version": "2.0.0", "dev": true, @@ -3359,22 +2873,6 @@ "wrappy": "1" } }, - "cli/node_modules/optionator": { - "version": "0.9.4", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "cli/node_modules/ox": { "version": "0.14.0", "dev": true, @@ -3545,14 +3043,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "cli/node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, "cli/node_modules/pretty-format": { "version": "29.7.0", "dev": true, @@ -3578,14 +3068,6 @@ "node": ">= 6" } }, - "cli/node_modules/punycode": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "cli/node_modules/randombytes": { "version": "2.1.0", "dev": true, @@ -3955,17 +3437,6 @@ "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } }, - "cli/node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "cli/node_modules/typechain": { "version": "8.3.2", "dev": true, @@ -4063,19 +3534,6 @@ "node": ">= 4.0.0" } }, - "cli/node_modules/typescript": { - "version": "5.8.3", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "cli/node_modules/typical": { "version": "4.0.0", "dev": true, @@ -4107,16 +3565,8 @@ "node": ">= 10.0.0" } }, - "cli/node_modules/uri-js": { - "version": "4.4.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "cli/node_modules/util-deprecate": { - "version": "1.0.2", + "cli/node_modules/util-deprecate": { + "version": "1.0.2", "dev": true, "license": "MIT" }, @@ -4228,14 +3678,6 @@ } } }, - "cli/node_modules/word-wrap": { - "version": "1.2.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "cli/node_modules/wordwrapjs": { "version": "4.0.1", "dev": true, @@ -4453,17 +3895,6 @@ "node": ">=8" } }, - "cli/node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "cli/node_modules/zod": { "version": "3.25.76", "dev": true, @@ -4724,6 +4155,179 @@ "prettier": "^2.7.1" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@inquirer/external-editor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", @@ -4861,6 +4465,46 @@ "resolved": "cli", "link": true }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/fs-extra": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/jsonfile": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", + "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "25.5.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", @@ -4870,90 +4514,416 @@ "undici-types": "~7.18.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.0.tgz", + "integrity": "sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==", "dev": true, "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/type-utils": "8.60.0", + "@typescript-eslint/utils": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.60.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 4" } }, - "node_modules/better-path-resolve": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", - "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "node_modules/@typescript-eslint/parser": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.0.tgz", + "integrity": "sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "is-windows": "^1.0.0" + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", + "debug": "^4.4.3" }, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.0.tgz", + "integrity": "sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==", + "dev": true, "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "@typescript-eslint/tsconfig-utils": "^8.60.0", + "@typescript-eslint/types": "^8.60.0", + "debug": "^4.4.3" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/chardet": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", - "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", - "license": "MIT" - }, - "node_modules/compose-documentation": { - "resolved": "website", - "link": true - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.0.tgz", + "integrity": "sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==", + "dev": true, "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0" }, "engines": { - "node": ">= 8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/detect-indent": { + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.0.tgz", + "integrity": "sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.0.tgz", + "integrity": "sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/utils": "8.60.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.0.tgz", + "integrity": "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.0.tgz", + "integrity": "sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.60.0", + "@typescript-eslint/tsconfig-utils": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.0.tgz", + "integrity": "sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.0.tgz", + "integrity": "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/compose-documentation": { + "resolved": "website", + "link": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-indent": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", @@ -4989,6 +4959,203 @@ "node": ">=8.6" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.0.tgz", + "integrity": "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -5002,6 +5169,49 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/extendable-error": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", @@ -5009,6 +5219,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -5025,6 +5241,19 @@ "node": ">=8.6.0" } }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -5034,6 +5263,19 @@ "reusify": "^1.0.4" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -5060,6 +5302,27 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, "node_modules/forge-std": { "version": "1.9.4", "resolved": "git+ssh://git@github.com/foundry-rs/forge-std.git#1eea5bae12ae557d589f9f0f0edae2faa47cb262", @@ -5154,6 +5417,15 @@ "node": ">= 4" } }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -5225,14 +5497,57 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, "node_modules/locate-path": { @@ -5277,6 +5592,22 @@ "node": ">=8.6" } }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -5287,6 +5618,37 @@ "node": ">=4" } }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/outdent": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", @@ -5422,6 +5784,16 @@ "node": ">=6" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/prettier": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", @@ -5438,6 +5810,15 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/quansync": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", @@ -5669,6 +6050,55 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5681,6 +6111,71 @@ "node": ">=8.0" } }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.0.tgz", + "integrity": "sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.60.0", + "@typescript-eslint/parser": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/utils": "8.60.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, "node_modules/undici-types": { "version": "7.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", @@ -5697,6 +6192,15 @@ "node": ">= 4.0.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5712,6 +6216,29 @@ "node": ">= 8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "src": { "name": "@perfect-abstractions/compose", "version": "0.0.3", @@ -10741,10 +11268,6 @@ "@types/estree": "*" } }, - "website/node_modules/@types/estree": { - "version": "1.0.8", - "license": "MIT" - }, "website/node_modules/@types/estree-jsx": { "version": "1.0.5", "license": "MIT", @@ -10828,10 +11351,6 @@ "@types/istanbul-lib-report": "*" } }, - "website/node_modules/@types/json-schema": { - "version": "7.0.15", - "license": "MIT" - }, "website/node_modules/@types/mdast": { "version": "4.0.4", "license": "MIT", @@ -11148,17 +11667,6 @@ "node": ">= 0.6" } }, - "website/node_modules/acorn": { - "version": "8.15.0", - "license": "MIT", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "website/node_modules/acorn-import-phases": { "version": "1.0.4", "license": "MIT", @@ -11169,13 +11677,6 @@ "acorn": "^8.14.0" } }, - "website/node_modules/acorn-jsx": { - "version": "5.3.2", - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, "website/node_modules/acorn-walk": { "version": "8.3.4", "license": "MIT", @@ -13374,21 +13875,6 @@ "version": "1.2.1", "license": "MIT" }, - "website/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "website/node_modules/decode-named-character-reference": { "version": "1.2.0", "license": "MIT", @@ -13875,16 +14361,6 @@ "version": "1.0.3", "license": "MIT" }, - "website/node_modules/escape-string-regexp": { - "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "website/node_modules/eslint-scope": { "version": "5.1.1", "license": "BSD-2-Clause", @@ -13896,23 +14372,6 @@ "node": ">=8.0.0" } }, - "website/node_modules/esrecurse": { - "version": "4.3.0", - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "website/node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "website/node_modules/estraverse": { "version": "4.3.0", "license": "BSD-2-Clause", @@ -14007,13 +14466,6 @@ "@types/estree": "^1.0.0" } }, - "website/node_modules/esutils": { - "version": "2.0.3", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "website/node_modules/eta": { "version": "2.2.0", "license": "MIT", @@ -14188,18 +14640,10 @@ "node": ">=0.10.0" } }, - "website/node_modules/fast-deep-equal": { - "version": "3.1.3", - "license": "MIT" - }, "website/node_modules/fast-fifo": { "version": "1.3.2", "license": "MIT" }, - "website/node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "license": "MIT" - }, "website/node_modules/fast-uri": { "version": "3.1.0", "funding": [ @@ -15286,13 +15730,6 @@ "node": ">=8" } }, - "website/node_modules/imurmurhash": { - "version": "0.1.4", - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, "website/node_modules/indent-string": { "version": "4.0.0", "license": "MIT", @@ -15670,10 +16107,6 @@ "node": ">=6" } }, - "website/node_modules/json-buffer": { - "version": "3.0.1", - "license": "MIT" - }, "website/node_modules/json-parse-even-better-errors": { "version": "2.3.1", "license": "MIT" @@ -15727,13 +16160,6 @@ "node": ">= 12" } }, - "website/node_modules/keyv": { - "version": "4.5.4", - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, "website/node_modules/khroma": { "version": "2.1.0" }, @@ -18147,10 +18573,6 @@ "node": ">=10" } }, - "website/node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, "website/node_modules/multicast-dns": { "version": "7.2.5", "license": "MIT", @@ -20222,13 +20644,6 @@ "once": "^1.3.1" } }, - "website/node_modules/punycode": { - "version": "2.3.1", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "website/node_modules/pupa": { "version": "3.3.0", "license": "MIT", @@ -22323,13 +22738,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "website/node_modules/uri-js": { - "version": "4.4.1", - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "website/node_modules/url-loader": { "version": "4.1.1", "license": "MIT", diff --git a/package.json b/package.json index dbec750e..1e413aa0 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,11 @@ "url": "https://github.com/Perfect-Abstractions/Compose.git" }, "devDependencies": { - "@changesets/cli": "^2.30.0" + "@changesets/cli": "^2.30.0", + "@types/fs-extra": "^11.0.4", + "typescript-eslint": "^8.60.0" + }, + "dependencies": { + "commander": "^13.1.0" } }