From bc34a1f1132f634398f6579ef51e9a91cd33e72c Mon Sep 17 00:00:00 2001 From: Carson <104383295+codebycarson@users.noreply.github.com> Date: Mon, 9 Mar 2026 17:04:40 -0400 Subject: [PATCH] refactor(create-sei): stabilize CLI architecture and test coverage - extract wizard logic into reusable lib module\n- expand unit and e2e coverage for create-sei flows\n- make e2e setup self-contained and auto-build CLI when needed\n- fix test tsconfig inheritance and create-sei build determinism --- .github/workflows/checks.yml | 3 + .github/workflows/coverage.yml | 3 + .gitignore | 1 + packages/create-sei/.gitignore | 4 +- packages/create-sei/package.json | 23 +- packages/create-sei/src/__tests__/e2e.test.ts | 275 ++++++++++++++++ packages/create-sei/src/__tests__/lib.test.ts | 290 +++++++++++++++++ .../create-sei/src/__tests__/tsconfig.json | 11 + packages/create-sei/src/lib.ts | 150 +++++++++ packages/create-sei/src/main.test.ts | 38 --- packages/create-sei/src/main.ts | 155 ++------- packages/create-sei/tsconfig.json | 13 +- pnpm-lock.yaml | 300 +----------------- 13 files changed, 788 insertions(+), 478 deletions(-) create mode 100644 packages/create-sei/src/__tests__/e2e.test.ts create mode 100644 packages/create-sei/src/__tests__/lib.test.ts create mode 100644 packages/create-sei/src/__tests__/tsconfig.json create mode 100644 packages/create-sei/src/lib.ts delete mode 100644 packages/create-sei/src/main.test.ts diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 81c0bcbd0..43d04be37 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -15,6 +15,9 @@ jobs: with: node-version-file: '.nvmrc' + - name: Install Bun + uses: oven-sh/setup-bun@v2 + - name: Install pnpm uses: pnpm/action-setup@v4 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f3292fa9b..c986e1d77 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -23,6 +23,9 @@ jobs: with: node-version-file: '.nvmrc' + - name: Install Bun + uses: oven-sh/setup-bun@v2 + - uses: browser-actions/setup-chrome@v1 - run: chrome --version diff --git a/.gitignore b/.gitignore index 86ca8e9ae..757e8bda3 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ Thumbs.db packages/registry/chain-registry packages/registry/community-assetlist +packages/create-sei/test-output-* diff --git a/packages/create-sei/.gitignore b/packages/create-sei/.gitignore index 72509c832..edb96d4b1 100644 --- a/packages/create-sei/.gitignore +++ b/packages/create-sei/.gitignore @@ -1,5 +1,3 @@ node_modules dist - -test -``` +test-output-* diff --git a/packages/create-sei/package.json b/packages/create-sei/package.json index 0a6ef816e..dcd8f4e9d 100644 --- a/packages/create-sei/package.json +++ b/packages/create-sei/package.json @@ -9,23 +9,24 @@ "module": "dist/main.js", "type": "module", "bin": "./dist/main.js", + "exports": { + ".": { + "import": "./dist/main.js" + } + }, "scripts": { - "build": "rm -rf dist && tsc && chmod +x dist/main.js && rsync -av --exclude-from=.rsyncignore ./templates/ ./dist/templates/ && rsync -av --exclude-from=.rsyncignore ./extensions/ ./dist/extensions/", - "dev": "node --loader ts-node/esm src/main.ts", - "test": "jest" + "build": "tsc -b --force && chmod +x dist/main.js && rsync -av --exclude-from=.rsyncignore ./templates/ ./dist/templates/ && rsync -av --exclude-from=.rsyncignore ./extensions/ ./dist/extensions/", + "dev": "tsc --watch", + "clean": "rm -rf dist", + "test": "bun test" }, "dependencies": { "boxen": "^7.1.1", "commander": "^12.1.0", "inquirer": "^9.2.15" }, - "devDependencies": { - "@jest/globals": "^29.7.0", - "@types/jest": "^29.5.12", - "@types/node": "^20.14.10", - "jest": "^29.7.0", - "ts-jest": "^29.1.2", - "ts-node": "^10.9.2", - "typescript": "^5.5.3" + + "publishConfig": { + "access": "public" } } diff --git a/packages/create-sei/src/__tests__/e2e.test.ts b/packages/create-sei/src/__tests__/e2e.test.ts new file mode 100644 index 000000000..71f934440 --- /dev/null +++ b/packages/create-sei/src/__tests__/e2e.test.ts @@ -0,0 +1,275 @@ +import { afterAll, beforeAll, describe, expect, test } from "bun:test"; +import * as fs from "node:fs"; +import path from "node:path"; + +const packageDir = path.resolve(import.meta.dir, "../.."); +const cliPath = path.join(packageDir, "dist", "main.js"); +const e2eDir = path.join(packageDir, "test-output-e2e"); +const e2eTmpDir = path.join(e2eDir, ".tmp"); +const baseProjectName = "e2e-basic"; +const precompilesProjectName = "e2e-precompiles"; +const e2eTmpDirEnv = `${e2eTmpDir}${path.sep}`; +const e2eSpawnEnv = { + ...process.env, + TMPDIR: e2eTmpDirEnv, + BUN_TMPDIR: e2eTmpDirEnv, +}; + +async function runCli( + args: string[], + cwd: string, +): Promise<{ stdout: string; stderr: string; exitCode: number }> { + const proc = Bun.spawn(["node", cliPath, ...args], { + cwd, + stdout: "pipe", + stderr: "pipe", + env: { ...process.env, NO_COLOR: "1" }, + }); + + const [stdout, stderr] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + ]); + const exitCode = await proc.exited; + + return { stdout, stderr, exitCode }; +} + +async function pathExists(targetPath: string): Promise { + return fs.promises + .access(targetPath) + .then(() => true) + .catch(() => false); +} + +async function ensureCliBuilt(): Promise { + if (await pathExists(cliPath)) { + return; + } + + const proc = Bun.spawn(["bun", "run", "build"], { + cwd: packageDir, + stdout: "pipe", + stderr: "pipe", + env: { ...process.env, NO_COLOR: "1" }, + }); + const [stdout, stderr] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + ]); + await proc.exited; + if (proc.exitCode !== 0 || !(await pathExists(cliPath))) { + throw new Error( + `Failed to build create-sei CLI before e2e tests.\nstdout:\n${stdout}\nstderr:\n${stderr}`, + ); + } +} + +async function ensureProject( + projectName: string, + args: string[] = [], +): Promise { + const projectDir = path.join(e2eDir, projectName); + if (await pathExists(projectDir)) { + return; + } + + const { exitCode, stderr } = await runCli( + ["app", "--name", projectName, ...args], + e2eDir, + ); + if (exitCode !== 0) { + throw new Error( + `Failed to create fixture project '${projectName}'.\nstderr:\n${stderr}`, + ); + } +} + +async function installDeps(projectDir: string): Promise { + const proc = Bun.spawn(["bun", "install"], { + cwd: projectDir, + stdout: "pipe", + stderr: "pipe", + env: e2eSpawnEnv, + }); + const [stdout, stderr] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + ]); + await proc.exited; + if (proc.exitCode !== 0) { + throw new Error( + `bun install failed in '${projectDir}'.\nstdout:\n${stdout}\nstderr:\n${stderr}`, + ); + } +} + +describe("create-sei CLI e2e", () => { + beforeAll(async () => { + await fs.promises.rm(e2eDir, { recursive: true, force: true }); + await fs.promises.mkdir(e2eDir, { recursive: true }); + await fs.promises.mkdir(e2eTmpDir, { recursive: true }); + await ensureCliBuilt(); + }, 120_000); + + afterAll(async () => { + await fs.promises.rm(e2eDir, { recursive: true, force: true }); + }, 120_000); + + test("app --name creates a project directory", async () => { + const projectName = "e2e-create-check"; + const { exitCode } = await runCli(["app", "--name", projectName], e2eDir); + expect(exitCode).toBe(0); + + const projectDir = path.join(e2eDir, projectName); + const exists = await pathExists(projectDir); + expect(exists).toBe(true); + }); + + test("generated project has valid package.json", async () => { + await ensureProject(baseProjectName); + const pkgPath = path.join(e2eDir, baseProjectName, "package.json"); + const raw = await fs.promises.readFile(pkgPath, "utf-8"); + const pkg = JSON.parse(raw); + + expect(pkg.scripts).toBeDefined(); + expect(pkg.scripts.dev).toBe("next dev"); + expect(pkg.scripts.build).toBe("next build"); + expect(pkg.dependencies).toBeDefined(); + expect(pkg.dependencies.next).toBeDefined(); + expect(pkg.dependencies.react).toBeDefined(); + expect(pkg.dependencies.viem).toBeDefined(); + }); + + test("generated project has expected file structure", async () => { + await ensureProject(baseProjectName); + const projectDir = path.join(e2eDir, baseProjectName); + const expectedFiles = [ + "package.json", + "tsconfig.json", + "next.config.mjs", + "src", + ]; + + for (const file of expectedFiles) { + const exists = await pathExists(path.join(projectDir, file)); + expect(exists).toBe(true); + } + }); + + test("generated project can install dependencies", async () => { + await ensureProject(baseProjectName); + const projectDir = path.join(e2eDir, baseProjectName); + await installDeps(projectDir); + + // node_modules should exist + const nmExists = await pathExists(path.join(projectDir, "node_modules")); + expect(nmExists).toBe(true); + }, 60_000); + + test("generated project can build successfully", async () => { + await ensureProject(baseProjectName); + const projectDir = path.join(e2eDir, baseProjectName); + await installDeps(projectDir); + + const proc = Bun.spawn(["bun", "run", "build"], { + cwd: projectDir, + stdout: "pipe", + stderr: "pipe", + env: e2eSpawnEnv, + }); + + const [stdout, stderr] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + ]); + await proc.exited; + const exitCode = proc.exitCode; + + if (exitCode !== 0) { + console.error("Build stdout:", stdout); + console.error("Build stderr:", stderr); + } + expect(exitCode).toBe(0); + }, 120_000); + + test("app --name --extension precompiles creates project with extension", async () => { + const projectName = "e2e-precompiles-create-check"; + const { exitCode, stdout } = await runCli( + ["app", "--name", projectName, "--extension", "precompiles"], + e2eDir, + ); + expect(exitCode).toBe(0); + expect(stdout).toContain("Applied extension: precompiles"); + + // Extension should have overwritten package.json + const pkgPath = path.join(e2eDir, projectName, "package.json"); + const pkg = JSON.parse(await fs.promises.readFile(pkgPath, "utf-8")); + expect(pkg.name).toBe("template-next-create-sei-app-precompiles"); + }); + + test("extension project can install dependencies", async () => { + await ensureProject(precompilesProjectName, ["--extension", "precompiles"]); + const projectDir = path.join(e2eDir, precompilesProjectName); + await installDeps(projectDir); + }, 60_000); + + test("extension project can build successfully", async () => { + await ensureProject(precompilesProjectName, ["--extension", "precompiles"]); + const projectDir = path.join(e2eDir, precompilesProjectName); + await installDeps(projectDir); + + const proc = Bun.spawn(["bun", "run", "build"], { + cwd: projectDir, + stdout: "pipe", + stderr: "pipe", + env: e2eSpawnEnv, + }); + + const [stdout, stderr] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + ]); + await proc.exited; + + if (proc.exitCode !== 0) { + console.error("Build stdout:", stdout); + console.error("Build stderr:", stderr); + } + expect(proc.exitCode).toBe(0); + }, 120_000); + + test("list-extensions command outputs available extensions", async () => { + const { exitCode, stdout } = await runCli(["list-extensions"], e2eDir); + expect(exitCode).toBe(0); + expect(stdout).toContain("Available extensions:"); + expect(stdout).toContain("precompiles"); + }); + + test("app with invalid name does not create directory", async () => { + const { exitCode, stdout } = await runCli( + ["app", "--name", "INVALID NAME!"], + e2eDir, + ); + expect(exitCode).toBe(0); + expect(stdout).toContain("Invalid package name"); + + const exists = await pathExists(path.join(e2eDir, "INVALID NAME!")); + expect(exists).toBe(false); + }); + + test("app with nonexistent extension falls back to base template", async () => { + const { exitCode, stdout } = await runCli( + ["app", "--name", "e2e-fallback", "--extension", "does-not-exist"], + e2eDir, + ); + expect(exitCode).toBe(0); + expect(stdout).toContain("Warning"); + expect(stdout).toContain("does-not-exist"); + + // Should still have created the project from base template + const pkgPath = path.join(e2eDir, "e2e-fallback", "package.json"); + const pkg = JSON.parse(await fs.promises.readFile(pkgPath, "utf-8")); + expect(pkg.scripts.dev).toBe("next dev"); + }); +}); diff --git a/packages/create-sei/src/__tests__/lib.test.ts b/packages/create-sei/src/__tests__/lib.test.ts new file mode 100644 index 000000000..d94a9bb6a --- /dev/null +++ b/packages/create-sei/src/__tests__/lib.test.ts @@ -0,0 +1,290 @@ +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import * as fs from "node:fs"; +import path from "node:path"; +import { + isValidDirectoryName, + listExtensions, + runWizard, + validateOptions, +} from "../lib.js"; + +const packageDir = path.resolve(import.meta.dir, "../.."); + +// ─── Unit Tests ────────────────────────────────────────────────────────────── + +describe("isValidDirectoryName", () => { + test("accepts simple lowercase names", () => { + expect(isValidDirectoryName("my-app")).toBe(true); + expect(isValidDirectoryName("my-dapp")).toBe(true); + expect(isValidDirectoryName("test123")).toBe(true); + }); + + test("rejects scoped npm names (contain slash which is illegal)", () => { + expect(isValidDirectoryName("@sei/my-app")).toBe(false); + expect(isValidDirectoryName("@scope/package-name")).toBe(false); + }); + + test("accepts names with dots and underscores", () => { + expect(isValidDirectoryName("my.app")).toBe(true); + expect(isValidDirectoryName("my_app")).toBe(true); + }); + + test("rejects empty string", () => { + expect(isValidDirectoryName("")).toBe(false); + }); + + test("rejects names with illegal characters", () => { + expect(isValidDirectoryName("myapp")).toBe(false); + expect(isValidDirectoryName('my"app')).toBe(false); + expect(isValidDirectoryName("my|app")).toBe(false); + expect(isValidDirectoryName("my?app")).toBe(false); + expect(isValidDirectoryName("my*app")).toBe(false); + }); + + test("rejects Windows reserved names", () => { + expect(isValidDirectoryName("con")).toBe(false); + expect(isValidDirectoryName("prn")).toBe(false); + expect(isValidDirectoryName("aux")).toBe(false); + expect(isValidDirectoryName("nul")).toBe(false); + expect(isValidDirectoryName("com1")).toBe(false); + expect(isValidDirectoryName("lpt1")).toBe(false); + expect(isValidDirectoryName("CON")).toBe(false); + expect(isValidDirectoryName("PRN")).toBe(false); + }); + + test("rejects names with trailing dots or spaces", () => { + expect(isValidDirectoryName("myapp.")).toBe(false); + expect(isValidDirectoryName("myapp ")).toBe(false); + expect(isValidDirectoryName("myapp..")).toBe(false); + }); + + test("rejects names that are not valid npm package names", () => { + expect(isValidDirectoryName("MyApp")).toBe(false); + expect(isValidDirectoryName("MY-APP")).toBe(false); + expect(isValidDirectoryName(".hidden")).toBe(false); + }); + + test("accepts hyphen-prefixed names (valid per npm regex)", () => { + expect(isValidDirectoryName("-startswithdash")).toBe(true); + }); +}); + +describe("validateOptions", () => { + test("returns true when no name is provided", () => { + expect(validateOptions({})).toBe(true); + }); + + test("returns true for valid name", () => { + expect(validateOptions({ name: "my-app" })).toBe(true); + }); + + test("returns false for invalid name", () => { + expect(validateOptions({ name: "INVALID NAME!" })).toBe(false); + }); + + test("returns true when only extension is provided", () => { + expect(validateOptions({ extension: "precompiles" })).toBe(true); + }); + + test("returns false for Windows reserved name", () => { + expect(validateOptions({ name: "con" })).toBe(false); + }); +}); + +// ─── Integration Tests ─────────────────────────────────────────────────────── + +describe("listExtensions", () => { + test("prints available extensions without throwing", async () => { + const logs: string[] = []; + const originalLog = console.log; + console.log = (...args: unknown[]) => logs.push(args.join(" ")); + + try { + await listExtensions(packageDir); + } finally { + console.log = originalLog; + } + + const output = logs.join("\n"); + expect(output).toContain("Available extensions:"); + expect(output).toContain("precompiles"); + }); + + test("prints message when extensions directory does not exist", async () => { + const logs: string[] = []; + const originalLog = console.log; + console.log = (...args: unknown[]) => logs.push(args.join(" ")); + + try { + await listExtensions("/nonexistent/path"); + } finally { + console.log = originalLog; + } + + expect(logs.join("\n")).toContain("No extensions directory found."); + }); + + test("prints message when extensions directory is empty", async () => { + const emptyDir = path.join(packageDir, "test-output-empty-ext"); + const extDir = path.join(emptyDir, "extensions"); + await fs.promises.mkdir(extDir, { recursive: true }); + + const logs: string[] = []; + const originalLog = console.log; + console.log = (...args: unknown[]) => logs.push(args.join(" ")); + + try { + await listExtensions(emptyDir); + } finally { + console.log = originalLog; + await fs.promises.rm(emptyDir, { recursive: true, force: true }); + } + + expect(logs.join("\n")).toContain("No extensions available."); + }); +}); + +describe("runWizard", () => { + const testDir = path.join(packageDir, "test-output-integration"); + + beforeEach(async () => { + await fs.promises.rm(testDir, { recursive: true, force: true }); + await fs.promises.mkdir(testDir, { recursive: true }); + }); + + afterEach(async () => { + await fs.promises.rm(testDir, { recursive: true, force: true }); + }); + + test("creates project from base template with --name", async () => { + const originalCwd = process.cwd; + process.cwd = () => testDir; + + try { + await runWizard({ name: "test-app" }, packageDir); + } finally { + process.cwd = originalCwd; + } + + const projectDir = path.join(testDir, "test-app"); + const exists = await fs.promises + .access(projectDir) + .then(() => true) + .catch(() => false); + expect(exists).toBe(true); + + // Verify key template files were copied + const packageJson = JSON.parse( + await fs.promises.readFile( + path.join(projectDir, "package.json"), + "utf-8", + ), + ); + expect(packageJson).toBeDefined(); + expect(packageJson.scripts).toBeDefined(); + expect(packageJson.scripts.dev).toBe("next dev"); + expect(packageJson.scripts.build).toBe("next build"); + }); + + test("applies extension overlay when --extension is provided", async () => { + const originalCwd = process.cwd; + process.cwd = () => testDir; + + try { + await runWizard( + { name: "test-ext-app", extension: "precompiles" }, + packageDir, + ); + } finally { + process.cwd = originalCwd; + } + + const projectDir = path.join(testDir, "test-ext-app"); + + // Extension's package.json should overwrite the base + const packageJson = JSON.parse( + await fs.promises.readFile( + path.join(projectDir, "package.json"), + "utf-8", + ), + ); + expect(packageJson.name).toBe("template-next-create-sei-app-precompiles"); + }); + + test("handles non-existent extension gracefully", async () => { + const originalCwd = process.cwd; + process.cwd = () => testDir; + + const logs: string[] = []; + const originalLog = console.log; + console.log = (...args: unknown[]) => logs.push(args.join(" ")); + + try { + await runWizard( + { name: "test-fallback-app", extension: "nonexistent" }, + packageDir, + ); + } finally { + process.cwd = originalCwd; + console.log = originalLog; + } + + // Project should still be created from base template + const projectDir = path.join(testDir, "test-fallback-app"); + const exists = await fs.promises + .access(projectDir) + .then(() => true) + .catch(() => false); + expect(exists).toBe(true); + + // Should warn about missing extension + expect(logs.some((l) => l.includes("Warning"))).toBe(true); + expect(logs.some((l) => l.includes("nonexistent"))).toBe(true); + }); + + test("does not create project when name is invalid", async () => { + const originalCwd = process.cwd; + process.cwd = () => testDir; + + try { + await runWizard({ name: "INVALID NAME!" }, packageDir); + } finally { + process.cwd = originalCwd; + } + + // No directory should have been created + const entries = await fs.promises.readdir(testDir); + expect(entries.length).toBe(0); + }); + + test("copies expected directory structure", async () => { + const originalCwd = process.cwd; + process.cwd = () => testDir; + + try { + await runWizard({ name: "test-structure" }, packageDir); + } finally { + process.cwd = originalCwd; + } + + const projectDir = path.join(testDir, "test-structure"); + + // Check key Next.js project files exist + const expectedFiles = [ + "package.json", + "tsconfig.json", + "next.config.mjs", + "src", + ]; + + for (const file of expectedFiles) { + const filePath = path.join(projectDir, file); + const exists = await fs.promises + .access(filePath) + .then(() => true) + .catch(() => false); + expect(exists).toBe(true); + } + }); +}); diff --git a/packages/create-sei/src/__tests__/tsconfig.json b/packages/create-sei/src/__tests__/tsconfig.json new file mode 100644 index 000000000..70c35bab8 --- /dev/null +++ b/packages/create-sei/src/__tests__/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "noEmit": true, + "composite": false, + "declaration": false, + "declarationMap": false, + "sourceMap": false + }, + "include": ["./**/*"] +} diff --git a/packages/create-sei/src/lib.ts b/packages/create-sei/src/lib.ts new file mode 100644 index 000000000..354807f33 --- /dev/null +++ b/packages/create-sei/src/lib.ts @@ -0,0 +1,150 @@ +import fs from "node:fs"; +import path, { dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import boxen from "boxen"; +import inquirer from "inquirer"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +export interface WizardOptions { + name?: string; + extension?: string; +} + +// Print welcome message +export const printWelcomeMessage = () => { + console.log( + boxen("Welcome to the SEI DApp Generator!", { + padding: 1, + margin: 1, + borderStyle: "double", + borderColor: "#932C23", + }), + ); +}; + +export function isValidDirectoryName(dirName: string) { + const illegalRe = /[<>:"/\\|?*]/g; + const windowsReservedRe = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i; + const trailingRe = /[. ]+$/; + const validNpmPackageRe = + /^(?:@[a-z0-9-*~][a-z0-9-*._~]*)?[a-z0-9-~][a-z0-9-._~]*$/; + + if (typeof dirName !== "string" || dirName.length === 0) { + return false; + } + + // Check for illegal characters, Windows reserved names, trailing spaces/dots + if ( + illegalRe.test(dirName) || + windowsReservedRe.test(dirName) || + trailingRe.test(dirName) || + !validNpmPackageRe.test(dirName) + ) { + return false; + } + + return true; +} + +export const validateOptions = (options: WizardOptions): boolean => { + let valid = true; + + if (options.name) { + if (!isValidDirectoryName(options.name)) { + console.log("Invalid package name. Please use a valid npm package name."); + valid = false; + } + } + + return valid; +}; + +export async function listExtensions(baseDir = __dirname): Promise { + const extensionsPath = path.join(baseDir, "extensions"); + + try { + const extensions = await fs.promises.readdir(extensionsPath, { + withFileTypes: true, + }); + const extensionDirs = extensions + .filter((dirent) => dirent.isDirectory()) + .map((dirent) => dirent.name); + + if (extensionDirs.length === 0) { + console.log("No extensions available."); + return; + } + + console.log("Available extensions:"); + for (const ext of extensionDirs) { + console.log(` - ${ext}`); + } + } catch { + console.log("No extensions directory found."); + } +} + +export async function runWizard( + options: WizardOptions, + baseDir = __dirname, +): Promise { + if (!validateOptions(options)) { + return; + } + + printWelcomeMessage(); + + let dAppName = ""; + if (options.name) { + dAppName = options.name; + } else { + const promptResult = await inquirer.prompt([ + { + type: "input", + name: "dAppName", + message: "What is your dApp (project) name?", + validate: (input: string) => { + return ( + isValidDirectoryName(input) || + "Invalid package name. Please use a valid npm package name." + ); + }, + }, + ]); + + dAppName = promptResult.dAppName; + } + + // Copy base template + const templateName = "next-template"; + const templatePath = path.join(baseDir, "templates", templateName); + const dst = path.join(process.cwd(), dAppName); + await fs.promises.cp(templatePath, dst, { recursive: true }); + + // Apply extension if specified + if (options.extension) { + const extensionPath = path.join(baseDir, "extensions", options.extension); + + try { + await fs.promises.access(extensionPath); + await fs.promises.cp(extensionPath, dst, { recursive: true }); + console.log(`Applied extension: ${options.extension}`); + } catch { + console.log( + `Warning: Extension '${options.extension}' not found. Continuing with base template.`, + ); + } + } + + const extensionText = options.extension + ? ` with ${options.extension} extension` + : ""; + console.log( + `Project setup complete! Using template ${templateName}${extensionText}\n`, + ); + console.log( + `To start your app, run: \n > cd ${dAppName} \n > bun install \n > bun dev\n`, + ); +} diff --git a/packages/create-sei/src/main.test.ts b/packages/create-sei/src/main.test.ts deleted file mode 100644 index 24c810199..000000000 --- a/packages/create-sei/src/main.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { describe, test, expect, beforeEach, afterEach } from '@jest/globals'; -import { promises as fs } from 'node:fs'; -import path from 'node:path'; - -describe('Extension System', () => { - const testDir = path.join(process.cwd(), 'test-output'); - const extensionsDir = path.join(process.cwd(), 'extensions'); - - beforeEach(async () => { - // Clean up test directory - try { - await fs.rm(testDir, { recursive: true, force: true }); - } catch (e) { - // Directory might not exist - } - await fs.mkdir(testDir, { recursive: true }); - }); - - afterEach(async () => { - // Clean up test directory - try { - await fs.rm(testDir, { recursive: true, force: true }); - } catch (e) { - // Directory might not exist - } - }); - - test('should list available extensions', async () => { - const extensionExists = await fs.access(path.join(extensionsDir, 'precompiles')) - .then(() => true) - .catch(() => false); - - expect(extensionExists).toBe(true); - - const extensionFiles = await fs.readdir(extensionsDir); - expect(extensionFiles).toContain('precompiles'); - }); -}); diff --git a/packages/create-sei/src/main.ts b/packages/create-sei/src/main.ts index 297faffae..5847a5098 100644 --- a/packages/create-sei/src/main.ts +++ b/packages/create-sei/src/main.ts @@ -1,158 +1,39 @@ #!/usr/bin/env node -import boxen from 'boxen'; -import inquirer from 'inquirer'; -import fs from 'node:fs'; -import path from 'node:path'; -import { dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { Command } from 'commander'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +import { Command } from "commander"; +import { listExtensions, runWizard, type WizardOptions } from "./lib.js"; const program = new Command(); - -// Print welcome message -const printWelcomeMessage = () => { - console.log( - boxen('Welcome to the SEI DApp Generator!', { - padding: 1, - margin: 1, - borderStyle: 'double', - borderColor: '#932C23' - }) - ); -}; - -interface WizardOptions { - name?: string; - extension?: string; -} - -function isValidDirectoryName(dirName) { - const illegalRe = /[<>:"/\\|?*]/g; - const windowsReservedRe = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i; - const trailingRe = /[. ]+$/; - const validNpmPackageRe = /^(?:@[a-z0-9-*~][a-z0-9-*._~]*)?[a-z0-9-~][a-z0-9-._~]*$/; - - if (typeof dirName !== 'string' || dirName.length === 0) { - return false; - } - - // Check for illegal characters, Windows reserved names, trailing spaces/dots - if (illegalRe.test(dirName) || windowsReservedRe.test(dirName) || trailingRe.test(dirName) || !validNpmPackageRe.test(dirName)) { - return false; - } - - return true; -} - -const validateOptions = (options: WizardOptions): boolean => { - let valid = true; - - if (options.name) { - if (!isValidDirectoryName(options.name)) { - console.log('Invalid package name. Please use a valid npm package name.'); - valid = false; - } - } - - return valid; -}; - -async function listExtensions(): Promise { - const extensionsPath = path.join(__dirname, 'extensions'); - - try { - const extensions = await fs.promises.readdir(extensionsPath, { withFileTypes: true }); - const extensionDirs = extensions.filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name); - - if (extensionDirs.length === 0) { - console.log('No extensions available.'); - return; - } - - console.log('Available extensions:'); - for (const ext of extensionDirs) { - console.log(` - ${ext}`); - } - } catch (error) { - console.log('No extensions directory found.'); - } -} - -async function runWizard(options: WizardOptions): Promise { - if (!validateOptions(options)) { - return; - } - - printWelcomeMessage(); - - let dAppName = ''; - if (options.name) { - dAppName = options.name; - } else { - const promptResult = await inquirer.prompt([ - { - type: 'input', - name: 'dAppName', - message: 'What is your dApp (project) name?', - validate: (input: string) => { - return isValidDirectoryName(input) || 'Invalid package name. Please use a valid npm package name.'; - } - } - ]); - - dAppName = promptResult.dAppName; - } - - // Copy base template - const templateName = 'next-template'; - const templatePath = path.join(__dirname, 'templates', templateName); - const dst = path.join(process.cwd(), dAppName); - await fs.promises.cp(templatePath, dst, { recursive: true }); - - // Apply extension if specified - if (options.extension) { - const extensionPath = path.join(__dirname, 'extensions', options.extension); - - try { - await fs.promises.access(extensionPath); - await fs.promises.cp(extensionPath, dst, { recursive: true }); - console.log(`Applied extension: ${options.extension}`); - } catch (error) { - console.log(`Warning: Extension '${options.extension}' not found. Continuing with base template.`); - } - } - - const extensionText = options.extension ? ` with ${options.extension} extension` : ''; - console.log(`Project setup complete! Using template ${templateName}${extensionText}\n`); - console.log(`To start your app, run: \n > cd ${dAppName} \n > pnpm \n > pnpm dev\n`); -} - program - .command('app') - .description('Create a new SEI dApp') - .option('--name ', 'Specify the name of your dApp. Name must be a valid package name.') - .option('--extension ', 'Specify an extension to apply to the base template') + .command("app") + .description("Create a new SEI dApp") + .option( + "--name ", + "Specify the name of your dApp. Name must be a valid package name.", + ) + .option( + "--extension ", + "Specify an extension to apply to the base template", + ) .action(async (options: WizardOptions) => { try { await runWizard(options); } catch (error) { - console.error('An error occurred:', error); + console.error("An error occurred:", error); + process.exit(1); } }); program - .command('list-extensions') - .description('List all available extensions') + .command("list-extensions") + .description("List all available extensions") .action(async () => { try { await listExtensions(); } catch (error) { - console.error('An error occurred:', error); + console.error("An error occurred:", error); + process.exit(1); } }); diff --git a/packages/create-sei/tsconfig.json b/packages/create-sei/tsconfig.json index 86b7187f0..e32e8c41f 100644 --- a/packages/create-sei/tsconfig.json +++ b/packages/create-sei/tsconfig.json @@ -1,8 +1,8 @@ { "extends": "../../tsconfig.base.json", - "exclude": ["node_modules", "dist", "test"], "compilerOptions": { "outDir": "./dist", + "rootDir": "./src", "target": "ES2020", "useDefineForClassFields": true, "lib": ["ES2020", "DOM", "DOM.Iterable"], @@ -15,5 +15,14 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src"] + "include": ["src/**/*"], + "exclude": [ + "node_modules", + "dist", + "test", + "src/__tests__", + "src/**/__tests__", + "src/tests", + "src/**/*.test.ts" + ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4af8e54b8..f140bc011 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,28 +51,6 @@ importers: inquirer: specifier: ^9.2.15 version: 9.3.7 - devDependencies: - '@jest/globals': - specifier: ^29.7.0 - version: 29.7.0 - '@types/jest': - specifier: ^29.5.12 - version: 29.5.14 - '@types/node': - specifier: ^20.14.10 - version: 20.19.12 - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)) - ts-jest: - specifier: ^29.1.2 - version: 29.4.1(@babel/core@7.28.3)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.3))(jest-util@30.2.0)(jest@29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)))(typescript@5.9.2) - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@20.19.12)(typescript@5.9.2) - typescript: - specifier: ^5.5.3 - version: 5.9.2 packages/ledger: dependencies: @@ -120,7 +98,7 @@ importers: version: 4.21.2 jest: specifier: ^30.0.3 - version: 30.1.3(@types/node@22.18.0)(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2)) + version: 30.1.3(@types/node@22.18.0)(ts-node@2.1.2) trieve-ts-sdk: specifier: ^0.0.121 version: 0.0.121 @@ -603,10 +581,6 @@ packages: '@cosmjs/utils@0.32.4': resolution: {integrity: sha512-D1Yc+Zy8oL/hkUkFUL/bwxvuDBzRGpc4cF7/SkdhxX4iHpSLgdOuTt1mhCh9+kl6NQREy9t7SYZ6xeW5gFe60w==} - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - '@dynamic-labs-wallet/browser-wallet-client@0.0.260': resolution: {integrity: sha512-CHUlALCZ6hRViUN/CpvDogu54hXLlc3NqeKW3Wu3DG2fFfWtkdTB4uUPnrTOd8f5uUAgAP55XSKnBAl+V6R2Gg==} @@ -1393,9 +1367,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@jsep-plugin/assignment@1.3.0': resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} engines: {node: '>= 10.16.0'} @@ -1483,6 +1454,7 @@ packages: '@mintlify/cli@4.0.701': resolution: {integrity: sha512-TWxZqPivFvfxMHpHcfYwIWFOpLYxw0v0SUiIVfIVbLkF8IVf29GhaXsqXMdnWqqz0WujDc4nicZUMzIW8JaFDg==} engines: {node: '>=18.0.0'} + deprecated: This version is deprecated. Please upgrade to version 4.0.423 or later. hasBin: true '@mintlify/common@1.0.513': @@ -1878,18 +1850,6 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - '@tsconfig/node10@1.0.11': - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} - - '@tsconfig/node12@1.0.11': - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - '@tsconfig/node14@1.0.3': - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - '@tsconfig/node16@1.0.4': - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} @@ -2250,10 +2210,6 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} - acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -2363,9 +2319,6 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -2948,9 +2901,6 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true - create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -3125,10 +3075,6 @@ packages: resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==} engines: {node: '>=0.3.1'} - diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -4864,6 +4810,7 @@ packages: mint@4.2.97: resolution: {integrity: sha512-4DDWOJ1qQPgq+kWHQDApcPVsC3NLoEqlEauiMWF8CGQx+StgPYH/tipQaS7v1F9qBsSxBaZ8GTw8n08YOmSZKA==} engines: {node: '>=18.0.0'} + deprecated: This version is deprecated. Please upgrade to version 4.0.423 or later. hasBin: true mipd@0.0.7: @@ -6100,20 +6047,6 @@ packages: jest-util: optional: true - ts-node@10.9.2: - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - ts-node@2.1.2: resolution: {integrity: sha512-vUZ/qMzK3zPt2pAMEM93bPWReBSjhh5A4ZFF7wpKvTVzK9A4d80T7GVFLKkZue1NKYyQVei5I37GT6JziUGLPQ==} hasBin: true @@ -6347,9 +6280,6 @@ packages: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} @@ -6560,10 +6490,6 @@ packages: resolution: {integrity: sha512-cUr+6jz1CH+E9wIGgFW5lyMMOHLbCe/UCOVqV/TTnf5XMe0NBC3TS7pR9ZpDsb84iCWKBd6ETPRBqQjssDKsIA==} engines: {node: '>=0.10.0'} - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -7269,10 +7195,6 @@ snapshots: '@cosmjs/utils@0.32.4': {} - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - '@dynamic-labs-wallet/browser-wallet-client@0.0.260(bufferutil@4.1.0)(utf-8-validate@5.0.10)': dependencies: '@dynamic-labs-wallet/core': 0.0.260(bufferutil@4.1.0)(utf-8-validate@5.0.10) @@ -8073,41 +7995,6 @@ snapshots: jest-util: 30.0.5 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2))': - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 20.19.12 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - '@jest/core@29.7.0(ts-node@2.1.2)': dependencies: '@jest/console': 29.7.0 @@ -8143,7 +8030,7 @@ snapshots: - supports-color - ts-node - '@jest/core@30.1.3(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2))': + '@jest/core@30.1.3(ts-node@2.1.2)': dependencies: '@jest/console': 30.1.2 '@jest/pattern': 30.0.1 @@ -8158,7 +8045,7 @@ snapshots: exit-x: 0.2.2 graceful-fs: 4.2.11 jest-changed-files: 30.0.5 - jest-config: 30.1.3(@types/node@22.18.0)(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2)) + jest-config: 30.1.3(@types/node@22.18.0)(ts-node@2.1.2) jest-haste-map: 30.1.0 jest-message-util: 30.1.0 jest-regex-util: 30.0.1 @@ -8489,11 +8376,6 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.5 optional: true - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)': dependencies: jsep: 1.4.0 @@ -9460,14 +9342,6 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} - '@tsconfig/node10@1.0.11': {} - - '@tsconfig/node12@1.0.11': {} - - '@tsconfig/node14@1.0.3': {} - - '@tsconfig/node16@1.0.4': {} - '@tybys/wasm-util@0.10.0': dependencies: tslib: 2.8.1 @@ -9827,10 +9701,6 @@ snapshots: dependencies: acorn: 8.15.0 - acorn-walk@8.3.4: - dependencies: - acorn: 8.15.0 - acorn@8.15.0: {} address@1.2.2: {} @@ -9915,8 +9785,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - arg@4.1.3: {} - arg@5.0.2: {} argon2id@1.0.1: {} @@ -10556,21 +10424,6 @@ snapshots: cosmjs-types@0.9.0: {} - create-jest@29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - create-jest@29.7.0(@types/node@22.18.0)(ts-node@2.1.2): dependencies: '@jest/types': 29.6.3 @@ -10586,8 +10439,6 @@ snapshots: - supports-color - ts-node - create-require@1.1.1: {} - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -10716,8 +10567,6 @@ snapshots: diff@3.5.0: {} - diff@4.0.2: {} - dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -12193,25 +12042,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest-cli@29.7.0(@types/node@22.18.0)(ts-node@2.1.2): dependencies: '@jest/core': 29.7.0(ts-node@2.1.2) @@ -12231,15 +12061,15 @@ snapshots: - supports-color - ts-node - jest-cli@30.1.3(@types/node@22.18.0)(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2)): + jest-cli@30.1.3(@types/node@22.18.0)(ts-node@2.1.2): dependencies: - '@jest/core': 30.1.3(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2)) + '@jest/core': 30.1.3(ts-node@2.1.2) '@jest/test-result': 30.1.3 '@jest/types': 30.0.5 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.1.3(@types/node@22.18.0)(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2)) + jest-config: 30.1.3(@types/node@22.18.0)(ts-node@2.1.2) jest-util: 30.0.5 jest-validate: 30.1.0 yargs: 17.7.2 @@ -12250,37 +12080,6 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)): - dependencies: - '@babel/core': 7.28.3 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.3) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 20.19.12 - ts-node: 10.9.2(@types/node@20.19.12)(typescript@5.9.2) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - jest-config@29.7.0(@types/node@20.19.12)(ts-node@2.1.2): dependencies: '@babel/core': 7.28.3 @@ -12343,7 +12142,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@30.1.3(@types/node@22.18.0)(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2)): + jest-config@30.1.3(@types/node@22.18.0)(ts-node@2.1.2): dependencies: '@babel/core': 7.28.3 '@jest/get-type': 30.1.0 @@ -12371,7 +12170,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 22.18.0 - ts-node: 10.9.2(@types/node@22.18.0)(typescript@5.9.2) + ts-node: 2.1.2 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -12841,18 +12640,6 @@ snapshots: supports-color: 8.1.1 optional: true - jest@29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)) - '@jest/types': 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest@29.7.0(@types/node@22.18.0)(ts-node@2.1.2): dependencies: '@jest/core': 29.7.0(ts-node@2.1.2) @@ -12865,12 +12652,12 @@ snapshots: - supports-color - ts-node - jest@30.1.3(@types/node@22.18.0)(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2)): + jest@30.1.3(@types/node@22.18.0)(ts-node@2.1.2): dependencies: - '@jest/core': 30.1.3(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2)) + '@jest/core': 30.1.3(ts-node@2.1.2) '@jest/types': 30.0.5 import-local: 3.2.0 - jest-cli: 30.1.3(@types/node@22.18.0)(ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2)) + jest-cli: 30.1.3(@types/node@22.18.0)(ts-node@2.1.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -15071,26 +14858,6 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.4.1(@babel/core@7.28.3)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.3))(jest-util@30.2.0)(jest@29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)))(typescript@5.9.2): - dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - handlebars: 4.7.8 - jest: 29.7.0(@types/node@20.19.12)(ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2)) - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.7.2 - type-fest: 4.41.0 - typescript: 5.9.2 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.28.3 - '@jest/transform': 30.2.0 - '@jest/types': 30.2.0 - babel-jest: 30.2.0(@babel/core@7.28.3) - jest-util: 30.2.0 - ts-jest@29.4.1(@babel/core@7.28.3)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.3))(jest-util@30.2.0)(jest@29.7.0(@types/node@22.18.0)(ts-node@2.1.2))(typescript@5.9.2): dependencies: bs-logger: 0.2.6 @@ -15111,43 +14878,6 @@ snapshots: babel-jest: 30.2.0(@babel/core@7.28.3) jest-util: 30.2.0 - ts-node@10.9.2(@types/node@20.19.12)(typescript@5.9.2): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.19.12 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.9.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - - ts-node@10.9.2(@types/node@22.18.0)(typescript@5.9.2): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 22.18.0 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.9.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optional: true - ts-node@2.1.2: dependencies: arrify: 1.0.1 @@ -15454,8 +15184,6 @@ snapshots: uuid@8.3.2: {} - v8-compile-cache-lib@3.0.1: {} - v8-to-istanbul@9.3.0: dependencies: '@jridgewell/trace-mapping': 0.3.30 @@ -15748,8 +15476,6 @@ snapshots: dependencies: object-assign: 4.1.1 - yn@3.1.1: {} - yocto-queue@0.1.0: {} yoctocolors-cjs@2.1.3: {}