From 64931eb7ffa9140080f5e53250db729a6362b521 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 5 Feb 2026 21:33:42 +0100 Subject: [PATCH] Replace ESLint and Prettier with Biome --- .gitignore | 7 + .release-it.json | 20 +- ai/rules/index.md | 4 + ai/rules/sudolang/index.md | 12 + ai/rules/user-testing.test.js | 7 +- bin/aidd.js | 50 +- bin/cli-help-e2e.test.js | 8 +- biome.json | 120 ++ eslint.config.mjs | 27 - lib/agents-index-e2e.test.js | 14 +- lib/agents-md.d.ts | 10 +- lib/agents-md.js | 6 +- lib/agents-md.test.js | 12 +- lib/cli-core.js | 70 +- lib/cli-core.test.js | 3 +- lib/cursor-symlink.test.js | 15 +- lib/error-conditions.test.js | 6 +- lib/index-generator.d.ts | 11 +- lib/index-generator.js | 14 +- lib/index-generator.test.js | 10 +- lib/release-helpers.js | 34 +- lib/release-process-e2e.test.js | 22 +- lib/update-latest-tag-hook.js | 2 +- package-lock.json | 1135 +++-------------- package.json | 104 +- release.js | 34 +- src/server/create-route.js | 10 +- src/server/create-route.test.js | 5 +- src/server/index.d.ts | 33 +- src/server/index.js | 16 +- src/server/middleware/handle-form.js | 6 +- src/server/middleware/handle-form.test.js | 5 +- src/server/middleware/index.js | 12 +- src/server/middleware/with-auth.js | 12 +- src/server/middleware/with-auth.test.js | 5 +- src/server/middleware/with-config.js | 2 +- src/server/middleware/with-config.test.js | 7 +- src/server/middleware/with-cors.js | 4 +- src/server/middleware/with-cors.test.js | 5 +- src/server/middleware/with-csrf.js | 16 +- src/server/middleware/with-csrf.test.js | 9 +- src/server/middleware/with-request-id.test.js | 7 +- src/server/middleware/with-server-error.js | 2 +- .../middleware/with-server-error.test.js | 5 +- src/server/test-utils.js | 2 +- tsconfig.json | 27 +- utils/index.d.ts | 13 +- utils/index.js | 2 +- vitest.config.js | 4 +- 49 files changed, 644 insertions(+), 1322 deletions(-) create mode 100644 ai/rules/sudolang/index.md create mode 100644 biome.json delete mode 100644 eslint.config.mjs diff --git a/.gitignore b/.gitignore index fa4fc0e..7b89c6d 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,10 @@ vite.config.ts.timestamp-* # Core dump files core core.* +.claude/ + +# Local AIDD database +.aidd/ + +# Local task files +tasks/ diff --git a/.release-it.json b/.release-it.json index 1a95b25..678a5ab 100644 --- a/.release-it.json +++ b/.release-it.json @@ -1,25 +1,25 @@ { "git": { "commitMessage": "chore(release): v${version}", - "tagName": "v${version}", + "requireBranch": ["main", "master"], "requireCleanWorkingDir": false, - "requireBranch": ["main", "master"] + "tagName": "v${version}" }, "github": { - "release": true, - "releaseName": "v${version}", "autoGenerate": { "template": "compact" - } - }, - "npm": { - "publish": true + }, + "release": true, + "releaseName": "v${version}" }, "hooks": { - "before:init": ["npm test"], "after:release": [ "node lib/update-latest-tag-hook.js ${version}", "echo 🎉 Successfully released ${name} v${version}" - ] + ], + "before:init": ["npm test"] + }, + "npm": { + "publish": true } } diff --git a/ai/rules/index.md b/ai/rules/index.md index da91dcb..6001f82 100644 --- a/ai/rules/index.md +++ b/ai/rules/index.md @@ -16,6 +16,10 @@ See [`javascript/index.md`](./javascript/index.md) for contents. See [`security/index.md`](./security/index.md) for contents. +### 📁 sudolang/ + +See [`sudolang/index.md`](./sudolang/index.md) for contents. + ## Files ### Aiden Agent Orchestrator diff --git a/ai/rules/sudolang/index.md b/ai/rules/sudolang/index.md new file mode 100644 index 0000000..b2f47e7 --- /dev/null +++ b/ai/rules/sudolang/index.md @@ -0,0 +1,12 @@ +# sudolang + +This index provides an overview of the contents in this directory. + +## Files + +### SudoLang Syntax + +**File:** `sudolang-syntax.mdc` + +A quick cheat sheet for SudoLang syntax. + diff --git a/ai/rules/user-testing.test.js b/ai/rules/user-testing.test.js index bad562f..9e2b7f9 100644 --- a/ai/rules/user-testing.test.js +++ b/ai/rules/user-testing.test.js @@ -1,8 +1,9 @@ -import { assert } from "riteway/vitest"; -import { describe, test } from "vitest"; -import fs from "fs-extra"; import path from "path"; import { fileURLToPath } from "url"; +import fs from "fs-extra"; +import { assert } from "riteway/vitest"; +import { describe, test } from "vitest"; + import { parseFrontmatter } from "../../lib/index-generator.js"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); diff --git a/bin/aidd.js b/bin/aidd.js index 859801d..227701b 100755 --- a/bin/aidd.js +++ b/bin/aidd.js @@ -1,14 +1,14 @@ #!/usr/bin/env node -import { Command } from "commander"; -import { executeClone } from "../lib/cli-core.js"; -import { generateAllIndexes } from "../lib/index-generator.js"; import { readFileSync } from "fs"; -import { fileURLToPath } from "url"; import path from "path"; import process from "process"; -import { errorCauses } from "error-causes"; +import { fileURLToPath } from "url"; import chalk from "chalk"; +import { Command } from "commander"; + +import { executeClone, handleCliErrors } from "../lib/cli-core.js"; +import { generateAllIndexes } from "../lib/index-generator.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -16,22 +16,6 @@ const packageJson = JSON.parse( readFileSync(path.join(__dirname, "../package.json"), "utf-8"), ); -// Use the same error causes as the CLI library -const [, handleCliErrors] = errorCauses({ - ValidationError: { - code: "VALIDATION_ERROR", - message: "Input validation failed", - }, - FileSystemError: { - code: "FILESYSTEM_ERROR", - message: "File system operation failed", - }, - CloneError: { - code: "CLONE_ERROR", - message: "AI folder cloning failed", - }, -}); - const createCli = () => { const program = new Command(); @@ -150,11 +134,11 @@ https://paralleldrive.com } const result = await executeClone({ - targetDirectory, - force, + cursor, dryRun, + force, + targetDirectory, verbose, - cursor, }); if (!result.success) { @@ -168,11 +152,14 @@ https://paralleldrive.com // Use handleErrors instead of manual switching try { handleCliErrors({ - ValidationError: ({ message }) => { - console.error(`❌ Validation Error: ${message}`); + CloneError: ({ message, cause }) => { + console.error(`❌ Clone Error: ${message}`); console.error( - "💡 Try using --force to overwrite existing files", + "💡 Check source directory and target permissions", ); + if (verbose && cause) { + console.error("🔍 Caused by:", cause.message || cause); + } }, FileSystemError: ({ message, cause }) => { console.error(`❌ File System Error: ${message}`); @@ -183,14 +170,11 @@ https://paralleldrive.com console.error("🔍 Caused by:", cause.message || cause); } }, - CloneError: ({ message, cause }) => { - console.error(`❌ Clone Error: ${message}`); + ValidationError: ({ message }) => { + console.error(`❌ Validation Error: ${message}`); console.error( - "💡 Check source directory and target permissions", + "💡 Try using --force to overwrite existing files", ); - if (verbose && cause) { - console.error("🔍 Caused by:", cause.message || cause); - } }, })(error); } catch { diff --git a/bin/cli-help-e2e.test.js b/bin/cli-help-e2e.test.js index c233bba..29abe99 100644 --- a/bin/cli-help-e2e.test.js +++ b/bin/cli-help-e2e.test.js @@ -1,9 +1,9 @@ -import { assert } from "riteway/vitest"; -import { describe, test } from "vitest"; import { exec } from "child_process"; -import { promisify } from "util"; -import { fileURLToPath } from "url"; import path from "path"; +import { fileURLToPath } from "url"; +import { promisify } from "util"; +import { assert } from "riteway/vitest"; +import { describe, test } from "vitest"; const execAsync = promisify(exec); const __filename = fileURLToPath(import.meta.url); diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..d1080e8 --- /dev/null +++ b/biome.json @@ -0,0 +1,120 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.12/schema.json", + "assist": { + "actions": { + "source": { + "organizeImports": { + "level": "on", + "options": { + "groups": [":NODE:", ":PACKAGE:", ":BLANK_LINE:", ":PATH:"] + } + }, + "useSortedAttributes": "on", + "useSortedKeys": "on" + } + }, + "enabled": true + }, + "css": { + "parser": { + "tailwindDirectives": true + } + }, + "files": { + "ignoreUnknown": false, + "includes": ["**", "!.react-router"] + }, + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + }, + "linter": { + "enabled": true, + "rules": { + "correctness": { + "noReactPropAssignments": "error", + "noUnusedFunctionParameters": "error", + "noUnusedImports": "error", + "noUnusedVariables": "error", + "useHookAtTopLevel": "error", + "useJsonImportAttributes": "error", + "useJsxKeyInIterable": "error", + "useSingleJsDocAsterisk": "error" + }, + "recommended": true, + "style": { + "noRestrictedGlobals": "off", + "useForOf": "error", + "useImportType": { + "level": "error", + "options": { + "style": "separatedType" + } + }, + "useNodejsImportProtocol": "off", + "useNumberNamespace": "error", + "useNumericSeparators": "error", + "useSelfClosingElements": "error", + "useTrimStartEnd": "error" + }, + "suspicious": { + "noDuplicateTestHooks": "error", + "noFocusedTests": "error", + "noGlobalIsFinite": "off", + "noGlobalIsNan": "error", + "noMisplacedAssertion": "error", + "noUnknownAtRules": "off" + } + } + }, + "overrides": [ + { + "includes": ["**/*.d.ts"], + "linter": { + "rules": { + "suspicious": { + "noExplicitAny": "off" + } + } + } + }, + { + "assist": { + "actions": { + "source": { + "useSortedKeys": "off" + } + } + }, + "includes": ["**/*.test.js", "**/*.test.ts", "**/*.test.tsx"], + "linter": { + "rules": { + "correctness": { + "noUnusedFunctionParameters": "off" + } + } + } + }, + { + "assist": { + "actions": { + "source": { + "useSortedKeys": "off" + } + } + }, + "includes": ["package.json"] + } + ], + "vcs": { + "clientKind": "git", + "defaultBranch": "main", + "enabled": true, + "useIgnoreFile": true + } +} diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index dd993ff..0000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import { dirname } from "path"; -import { fileURLToPath } from "url"; -import { FlatCompat } from "@eslint/eslintrc"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -const compat = new FlatCompat({ - baseDirectory: __dirname, -}); - -const eslintConfig = [ - ...compat.extends("prettier"), - { - plugins: { - prettier: (await import("eslint-plugin-prettier")).default, - }, - rules: { - "prettier/prettier": "error", - }, - }, - { - ignores: ["node_modules/**", "coverage/**"], - }, -]; - -export default eslintConfig; diff --git a/lib/agents-index-e2e.test.js b/lib/agents-index-e2e.test.js index 48daff3..9b883e4 100644 --- a/lib/agents-index-e2e.test.js +++ b/lib/agents-index-e2e.test.js @@ -1,13 +1,13 @@ -import { assert } from "riteway/vitest"; -import { describe, test, beforeEach, afterEach } from "vitest"; import { exec } from "child_process"; -import { promisify } from "util"; -import fs from "fs-extra"; import path from "path"; import { fileURLToPath } from "url"; +import { promisify } from "util"; +import fs from "fs-extra"; +import { assert } from "riteway/vitest"; +import { afterEach, beforeEach, describe, test } from "vitest"; -import { executeClone } from "./cli-core.js"; import { hasAllDirectives } from "./agents-md.js"; +import { executeClone } from "./cli-core.js"; const execAsync = promisify(exec); const __filename = fileURLToPath(import.meta.url); @@ -188,9 +188,7 @@ This is a test rule. }); test("--index generates index.md files", async () => { - const { stdout, stderr } = await execAsync( - `node ${cliPath} --index "${tempTestDir}"`, - ); + await execAsync(`node ${cliPath} --index "${tempTestDir}"`); const aiIndexExists = await fs.pathExists(path.join(aiPath, "index.md")); const commandsIndexExists = await fs.pathExists( diff --git a/lib/agents-md.d.ts b/lib/agents-md.d.ts index 6fc6f83..ec1d1c1 100644 --- a/lib/agents-md.d.ts +++ b/lib/agents-md.d.ts @@ -48,14 +48,20 @@ export function getMissingDirectives(content: string): string[]; * @param content - Content to write * @throws {Error} If file cannot be written */ -export function writeAgentsFile(targetBase: string, content: string): Promise; +export function writeAgentsFile( + targetBase: string, + content: string, +): Promise; /** * Append directives to existing AGENTS.md * @param targetBase - Base directory containing AGENTS.md * @param existingContent - Current content of AGENTS.md */ -export function appendDirectives(targetBase: string, existingContent: string): Promise; +export function appendDirectives( + targetBase: string, + existingContent: string, +): Promise; /** * Ensure AGENTS.md exists with required directives diff --git a/lib/agents-md.js b/lib/agents-md.js index 8a0474b..5c07c6a 100644 --- a/lib/agents-md.js +++ b/lib/agents-md.js @@ -1,6 +1,6 @@ import path from "path"; +import { createError, errorCauses } from "error-causes"; import fs from "fs-extra"; -import { errorCauses, createError } from "error-causes"; // Error causes for AGENTS.md operations const [{ AgentsFileError }] = errorCauses({ @@ -85,8 +85,8 @@ const readAgentsFile = async (targetBase) => { } catch (originalError) { throw createError({ ...AgentsFileError, - message: `Failed to read AGENTS.md: ${agentsPath}`, cause: originalError, + message: `Failed to read AGENTS.md: ${agentsPath}`, }); } }; @@ -121,8 +121,8 @@ const writeAgentsFile = async (targetBase, content) => { } catch (originalError) { throw createError({ ...AgentsFileError, - message: `Failed to write AGENTS.md: ${agentsPath}`, cause: originalError, + message: `Failed to write AGENTS.md: ${agentsPath}`, }); } }; diff --git a/lib/agents-md.test.js b/lib/agents-md.test.js index c91c9a4..a200b94 100644 --- a/lib/agents-md.test.js +++ b/lib/agents-md.test.js @@ -1,15 +1,15 @@ -import { assert } from "riteway/vitest"; -import { describe, test, beforeEach, afterEach } from "vitest"; +import os from "os"; import path from "path"; import fs from "fs-extra"; -import os from "os"; +import { assert } from "riteway/vitest"; +import { afterEach, beforeEach, describe, test } from "vitest"; import { - ensureAgentsMd, + AGENTS_MD_CONTENT, agentsFileExists, - hasAllDirectives, + ensureAgentsMd, getMissingDirectives, - AGENTS_MD_CONTENT, + hasAllDirectives, REQUIRED_DIRECTIVES, } from "./agents-md.js"; diff --git a/lib/cli-core.js b/lib/cli-core.js index 7ba43c2..b14437b 100644 --- a/lib/cli-core.js +++ b/lib/cli-core.js @@ -1,9 +1,10 @@ import path from "path"; -import fs from "fs-extra"; -import chalk from "chalk"; import process from "process"; import { fileURLToPath } from "url"; -import { errorCauses, createError } from "error-causes"; +import chalk from "chalk"; +import { createError, errorCauses } from "error-causes"; +import fs from "fs-extra"; + import { ensureAgentsMd } from "./agents-md.js"; const __filename = fileURLToPath(import.meta.url); @@ -11,17 +12,17 @@ const __dirname = path.dirname(__filename); // Error causes definition using error-causes library const [cliErrors, handleCliErrors] = errorCauses({ - ValidationError: { - code: "VALIDATION_ERROR", - message: "Input validation failed", + CloneError: { + code: "CLONE_ERROR", + message: "AI folder cloning failed", }, FileSystemError: { code: "FILESYSTEM_ERROR", message: "File system operation failed", }, - CloneError: { - code: "CLONE_ERROR", - message: "AI folder cloning failed", + ValidationError: { + code: "VALIDATION_ERROR", + message: "Input validation failed", }, }); @@ -33,10 +34,10 @@ const resolvePaths = ({ packageRoot = __dirname, } = {}) => ({ source: path.resolve(packageRoot, "../ai"), - targetBase: path.resolve(process.cwd(), targetDirectory), get target() { return path.join(this.targetBase, "ai"); }, + targetBase: path.resolve(process.cwd(), targetDirectory), }); const validateSource = async ({ source }) => { @@ -72,8 +73,8 @@ const ensureTargetDir = } catch (originalError) { throw createError({ ...FileSystemError, - message: `Failed to create target directory: ${targetBase}`, cause: originalError, + message: `Failed to create target directory: ${targetBase}`, }); } }; @@ -91,7 +92,7 @@ const listDirectoryTree = if (stats.isDirectory()) { results.push(`${prefix}📁 ${item}/`); - const subResults = await listDirectoryTree(itemPath)(prefix + " "); + const subResults = await listDirectoryTree(itemPath)(`${prefix} `); results.push(...subResults); } else { results.push(`${prefix}📄 ${item}`); @@ -102,8 +103,8 @@ const listDirectoryTree = } catch (originalError) { throw createError({ ...FileSystemError, - message: `Failed to read directory: ${dirPath}`, cause: originalError, + message: `Failed to read directory: ${dirPath}`, }); } }; @@ -116,8 +117,8 @@ const copyDirectory = } catch (originalError) { throw createError({ ...CloneError, - message: `Failed to copy ai/ folder from ${source} to ${target}`, cause: originalError, + message: `Failed to copy ai/ folder from ${source} to ${target}`, }); } }; @@ -153,22 +154,22 @@ const createCursorSymlink = throw createError({ ...FileSystemError, - message: `Failed to create .cursor symlink: ${originalError.message}`, cause: originalError, + message: `Failed to create .cursor symlink: ${originalError.message}`, }); } }; // Output functions const createLogger = ({ verbose = false, dryRun = false } = {}) => ({ - info: (msg) => console.log(chalk.blue(msg)), - success: (msg) => console.log(chalk.green(msg)), - warning: (msg) => console.log(chalk.yellow(msg)), + cyan: (msg) => console.log(chalk.cyan(msg)), + dryRun: (msg) => dryRun && console.log(chalk.yellow(msg)), error: (msg) => console.error(chalk.red(msg)), gray: (msg) => console.log(chalk.gray(msg)), - cyan: (msg) => console.log(chalk.cyan(msg)), + info: (msg) => console.log(chalk.blue(msg)), + success: (msg) => console.log(chalk.green(msg)), verbose: (msg) => verbose && console.log(chalk.gray(msg)), - dryRun: (msg) => dryRun && console.log(chalk.yellow(msg)), + warning: (msg) => console.log(chalk.yellow(msg)), }); const formatHeader = @@ -210,12 +211,12 @@ const executeClone = async ({ cursor = false, } = {}) => { try { - const logger = createLogger({ verbose, dryRun }); + const logger = createLogger({ dryRun, verbose }); const paths = resolvePaths({ targetDirectory }); // Validation pipeline - now throws structured errors await validateSource(paths); - await validateTarget({ target: paths.target, force })(); + await validateTarget({ force, target: paths.target })(); // Output header formatHeader({ ...paths, verbose })(logger); @@ -227,10 +228,10 @@ const executeClone = async ({ // Dry run: show what would be copied formatDryRunHeader()(logger); const fileList = await listDirectoryTree(paths.source)(); - fileList.forEach((file) => - file.includes("📁") ? logger.info(file) : logger.gray(file), - ); - return { success: true, dryRun: true }; + for (const file of fileList) { + file.includes("📁") ? logger.info(file) : logger.gray(file); + } + return { dryRun: true, success: true }; } // Actual copy operation @@ -245,42 +246,43 @@ const executeClone = async ({ // Create cursor symlink if requested if (cursor) { verbose && logger.info("Creating .cursor symlink..."); - await createCursorSymlink({ targetBase: paths.targetBase, force })(); + await createCursorSymlink({ force, targetBase: paths.targetBase })(); } // Success output formatSuccess()(logger); - return { success: true, paths }; + return { paths, success: true }; } catch (error) { // Structured error handling using error causes if (error.cause) { return { - success: false, error: { - message: error.message, - code: error.cause?.code, cause: error.cause, + code: error.cause?.code, + message: error.message, }, + success: false, }; } // Handle unexpected errors return { - success: false, error: { + cause: error.cause, message: error.message, type: "unexpected", - cause: error.cause, }, + success: false, }; } }; export { + createLogger, executeClone, + handleCliErrors, resolvePaths, validateSource, validateTarget, - createLogger, }; diff --git a/lib/cli-core.test.js b/lib/cli-core.test.js index c2e8786..aacc1eb 100644 --- a/lib/cli-core.test.js +++ b/lib/cli-core.test.js @@ -1,7 +1,7 @@ import { assert } from "riteway/vitest"; import { describe, test } from "vitest"; -import { resolvePaths, createLogger } from "./cli-core.js"; +import { createLogger, resolvePaths } from "./cli-core.js"; describe("resolvePaths", () => { test("default path resolution", () => { @@ -54,7 +54,6 @@ describe("createLogger", () => { test("verbose logging flag", () => { const verboseLogger = createLogger({ verbose: true }); - const defaultLogger = createLogger({ verbose: false }); assert({ given: "verbose logging enabled", diff --git a/lib/cursor-symlink.test.js b/lib/cursor-symlink.test.js index 410c06d..fe0a99b 100644 --- a/lib/cursor-symlink.test.js +++ b/lib/cursor-symlink.test.js @@ -1,8 +1,8 @@ -import { assert } from "riteway/vitest"; -import { describe, test, beforeEach, afterEach } from "vitest"; -import fs from "fs-extra"; import path from "path"; import { fileURLToPath } from "url"; +import fs from "fs-extra"; +import { assert } from "riteway/vitest"; +import { afterEach, beforeEach, describe, test } from "vitest"; import { executeClone } from "./cli-core.js"; @@ -11,7 +11,6 @@ const __dirname = path.dirname(__filename); describe("cursor symlink functionality", () => { const tempTestDir = path.join(__dirname, "temp-cursor-test"); - const aiPath = path.join(tempTestDir, "ai"); const cursorPath = path.join(tempTestDir, ".cursor"); beforeEach(async () => { @@ -30,7 +29,7 @@ describe("cursor symlink functionality", () => { }); test("cursor option false should not create symlink", async () => { - const result = await executeClone({ + await executeClone({ targetDirectory: tempTestDir, cursor: false, }); @@ -46,7 +45,7 @@ describe("cursor symlink functionality", () => { }); test("cursor option true should create symlink to ai folder", async () => { - const result = await executeClone({ + await executeClone({ targetDirectory: tempTestDir, cursor: true, }); @@ -62,7 +61,7 @@ describe("cursor symlink functionality", () => { }); test("created symlink should point to ai folder", async () => { - const result = await executeClone({ + await executeClone({ targetDirectory: tempTestDir, cursor: true, }); @@ -113,7 +112,7 @@ describe("cursor symlink functionality", () => { // Create existing .cursor file (not a symlink) await fs.writeFile(cursorPath, "existing content"); - const result = await executeClone({ + await executeClone({ targetDirectory: tempTestDir, cursor: true, force: true, diff --git a/lib/error-conditions.test.js b/lib/error-conditions.test.js index 816d85c..e8bbf17 100644 --- a/lib/error-conditions.test.js +++ b/lib/error-conditions.test.js @@ -1,8 +1,8 @@ -import { assert } from "riteway/vitest"; -import { describe, test, beforeEach, afterEach } from "vitest"; -import fs from "fs-extra"; import path from "path"; import { fileURLToPath } from "url"; +import fs from "fs-extra"; +import { assert } from "riteway/vitest"; +import { afterEach, describe, test } from "vitest"; import { validateSource, validateTarget } from "./cli-core.js"; diff --git a/lib/index-generator.d.ts b/lib/index-generator.d.ts index 4021a09..87b0174 100644 --- a/lib/index-generator.d.ts +++ b/lib/index-generator.d.ts @@ -57,7 +57,10 @@ export function getSubdirectories(dirPath: string): Promise; * @param dirPath - Directory containing the file * @param filename - Name of the file */ -export function generateFileEntry(dirPath: string, filename: string): Promise; +export function generateFileEntry( + dirPath: string, + filename: string, +): Promise; /** * Generate markdown entry for a subdirectory @@ -85,7 +88,7 @@ export function writeIndex(dirPath: string): Promise; */ export function generateIndexRecursive( dirPath: string, - results?: IndexWriteResult[] + results?: IndexWriteResult[], ): Promise; /** @@ -100,4 +103,6 @@ export function generateIndexRecursive( * console.log(`Generated ${result.indexes.length} files`); * } */ -export function generateAllIndexes(targetBase: string): Promise; +export function generateAllIndexes( + targetBase: string, +): Promise; diff --git a/lib/index-generator.js b/lib/index-generator.js index 480c563..005a23e 100644 --- a/lib/index-generator.js +++ b/lib/index-generator.js @@ -1,7 +1,7 @@ import path from "path"; +import { createError, errorCauses } from "error-causes"; import fs from "fs-extra"; import matter from "gray-matter"; -import { errorCauses, createError } from "error-causes"; // Error causes for index generation operations const [{ IndexGenerationError }] = errorCauses({ @@ -201,8 +201,8 @@ const writeIndex = async (dirPath) => { } catch (originalError) { throw createError({ ...IndexGenerationError, - message: `Failed to write index.md: ${indexPath}`, cause: originalError, + message: `Failed to write index.md: ${indexPath}`, }); } }; @@ -246,27 +246,27 @@ const generateAllIndexes = async (targetBase) => { const exists = await fs.pathExists(aiPath); if (!exists) { return { - success: false, error: `ai/ directory not found at ${aiPath}`, indexes: [], + success: false, }; } try { const results = await generateIndexRecursive(aiPath); return { - success: true, - message: `Generated ${results.length} index file(s)`, indexes: results, + message: `Generated ${results.length} index file(s)`, + success: true, }; } catch (error) { return { - success: false, error: { - message: error?.message || String(error), cause: error?.cause, + message: error?.message || String(error), }, indexes: [], + success: false, }; } }; diff --git a/lib/index-generator.test.js b/lib/index-generator.test.js index 4bc4d4b..4961ac7 100644 --- a/lib/index-generator.test.js +++ b/lib/index-generator.test.js @@ -1,16 +1,16 @@ -import { assert } from "riteway/vitest"; -import { describe, test, beforeEach, afterEach } from "vitest"; +import os from "os"; import path from "path"; import fs from "fs-extra"; -import os from "os"; +import { assert } from "riteway/vitest"; +import { afterEach, beforeEach, describe, test } from "vitest"; import { + extractTitle, generateAllIndexes, generateIndexContent, - parseFrontmatter, - extractTitle, getIndexableFiles, getSubdirectories, + parseFrontmatter, } from "./index-generator.js"; describe("index-generator", () => { diff --git a/lib/release-helpers.js b/lib/release-helpers.js index 501faa9..0d6e520 100644 --- a/lib/release-helpers.js +++ b/lib/release-helpers.js @@ -1,8 +1,9 @@ -import { asyncPipe } from "../utils/async-pipe.js"; import { exec } from "child_process"; import { promisify } from "util"; import { createError } from "error-causes"; +import { asyncPipe } from "../utils/async-pipe.js"; + const execAsync = promisify(exec); const isPrerelease = (version = "") => { @@ -23,22 +24,22 @@ const validateVersionForLatestTag = async ({ } = {}) => { if (!shouldUpdateLatestTag(version)) { throw createError({ - name: "ValidationError", - message: `Cannot update latest tag: ${version} is a prerelease version`, code: "PRERELEASE_VERSION", + message: `Cannot update latest tag: ${version} is a prerelease version`, + name: "ValidationError", requestedVersion: version, }); } - return { version, dryRun }; + return { dryRun, version }; }; // Pure side effect - assumes valid input const performLatestTagUpdate = async ({ version, dryRun = false }) => { if (dryRun) { return { - success: true, message: `Would update latest tag to ${version}`, operation: "dry-run", + success: true, }; } @@ -55,33 +56,20 @@ const performLatestTagUpdate = async ({ version, dryRun = false }) => { await execAsync(`git push origin latest --force`); return { - success: true, message: `Updated latest tag to ${version} (${commitRef.substring(0, 7)}) and pushed to origin`, operation: "update", + success: true, }; } catch (originalError) { throw createError({ - name: "GitOperationError", - message: `Failed to update latest tag: ${originalError.message}`, - code: "GIT_OPERATION_FAILED", cause: originalError, + code: "GIT_OPERATION_FAILED", + message: `Failed to update latest tag: ${originalError.message}`, + name: "GitOperationError", }); } }; -// Error handler that converts thrown errors to result objects -const handleLatestTagErrors = async (input) => { - try { - return await performLatestTagUpdate(input); - } catch (error) { - return { - success: false, - message: error.message, - operation: "error", - }; - } -}; - // Composed pipeline with error handling const updateLatestTag = async (input) => { try { @@ -91,9 +79,9 @@ const updateLatestTag = async (input) => { )(input); } catch (error) { return { - success: false, message: error.message, operation: "error", + success: false, }; } }; diff --git a/lib/release-process-e2e.test.js b/lib/release-process-e2e.test.js index 026aac5..7ab1637 100644 --- a/lib/release-process-e2e.test.js +++ b/lib/release-process-e2e.test.js @@ -1,17 +1,14 @@ -import { assert } from "riteway/vitest"; -import { describe, test, beforeEach, afterEach } from "vitest"; import { exec } from "child_process"; -import { promisify } from "util"; -import fs from "fs-extra"; import path from "path"; +import { promisify } from "util"; +import { assert } from "riteway/vitest"; +import { afterEach, beforeEach, describe, test } from "vitest"; const execAsync = promisify(exec); describe("Enhanced Release Process E2E", () => { let originalLatestRef = null; let testTagsCreated = []; - let originalPackageVersion = null; - beforeEach(async () => { // Store current latest ref if it exists try { @@ -20,11 +17,6 @@ describe("Enhanced Release Process E2E", () => { } catch { originalLatestRef = null; } - - // Store original package.json version - const packagePath = path.join(process.cwd(), "package.json"); - const packageContent = await fs.readJson(packagePath); - originalPackageVersion = packageContent.version; }); afterEach(async () => { @@ -53,14 +45,6 @@ describe("Enhanced Release Process E2E", () => { // If restore fails, that's a problem but don't fail the test } } - - // Restore original package.json version - if (originalPackageVersion) { - const packagePath = path.join(process.cwd(), "package.json"); - const packageContent = await fs.readJson(packagePath); - packageContent.version = originalPackageVersion; - await fs.writeJson(packagePath, packageContent, { spaces: 2 }); - } }); test("hook integration with stable version", async () => { diff --git a/lib/update-latest-tag-hook.js b/lib/update-latest-tag-hook.js index 80f8793..91c88a2 100644 --- a/lib/update-latest-tag-hook.js +++ b/lib/update-latest-tag-hook.js @@ -16,8 +16,8 @@ const main = async () => { try { const result = await updateLatestTag({ - version: version.replace(/^v/, ""), // Remove 'v' prefix if present dryRun: false, + version: version.replace(/^v/, ""), // Remove 'v' prefix if present }); if (result.success) { diff --git a/package-lock.json b/package-lock.json index c11c74d..c230fd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,14 +22,10 @@ "aidd": "bin/aidd.js" }, "devDependencies": { - "@eslint/eslintrc": "^3", + "@biomejs/biome": "2.3.12", "@vitest/coverage-v8": "^3.2.4", "doctoc": "^2.2.1", - "eslint": "^9", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-prettier": "^5.5.4", "husky": "^9.1.7", - "prettier": "^3.6.2", "release-it": "^19.0.5", "riteway": "^9.0.0-rc.1", "typescript": "^5.9.3", @@ -118,6 +114,169 @@ "node": ">=18" } }, + "node_modules/@biomejs/biome": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.12.tgz", + "integrity": "sha512-AR7h4aSlAvXj7TAajW/V12BOw2EiS0AqZWV5dGozf4nlLoUF/ifvD0+YgKSskT0ylA6dY1A8AwgP8kZ6yaCQnA==", + "dev": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "2.3.12", + "@biomejs/cli-darwin-x64": "2.3.12", + "@biomejs/cli-linux-arm64": "2.3.12", + "@biomejs/cli-linux-arm64-musl": "2.3.12", + "@biomejs/cli-linux-x64": "2.3.12", + "@biomejs/cli-linux-x64-musl": "2.3.12", + "@biomejs/cli-win32-arm64": "2.3.12", + "@biomejs/cli-win32-x64": "2.3.12" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.12.tgz", + "integrity": "sha512-cO6fn+KiMBemva6EARDLQBxeyvLzgidaFRJi8G7OeRqz54kWK0E+uSjgFaiHlc3DZYoa0+1UFE8mDxozpc9ieg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.12.tgz", + "integrity": "sha512-/fiF/qmudKwSdvmSrSe/gOTkW77mHHkH8Iy7YC2rmpLuk27kbaUOPa7kPiH5l+3lJzTUfU/t6x1OuIq/7SGtxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.12.tgz", + "integrity": "sha512-nbOsuQROa3DLla5vvsTZg+T5WVPGi9/vYxETm9BOuLHBJN3oWQIg3MIkE2OfL18df1ZtNkqXkH6Yg9mdTPem7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.12.tgz", + "integrity": "sha512-aqkeSf7IH+wkzFpKeDVPSXy9uDjxtLpYA6yzkYsY+tVjwFFirSuajHDI3ul8en90XNs1NA0n8kgBrjwRi5JeyA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.12.tgz", + "integrity": "sha512-CQtqrJ+qEEI8tgRSTjjzk6wJAwfH3wQlkIGsM5dlecfRZaoT+XCms/mf7G4kWNexrke6mnkRzNy6w8ebV177ow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.12.tgz", + "integrity": "sha512-kVGWtupRRsOjvw47YFkk5mLiAdpCPMWBo1jOwAzh+juDpUb2sWarIp+iq+CPL1Wt0LLZnYtP7hH5kD6fskcxmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.12.tgz", + "integrity": "sha512-Re4I7UnOoyE4kHMqpgtG6UvSBGBbbtvsOvBROgCCoH7EgANN6plSQhvo2W7OCITvTp7gD6oZOyZy72lUdXjqZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.12.tgz", + "integrity": "sha512-qqGVWqNNek0KikwPZlOIoxtXgsNGsX+rgdEzgw82Re8nF02W+E2WokaQhpF5TdBh/D/RQ3TLppH+otp6ztN0lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.10", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", @@ -560,223 +719,6 @@ "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", - "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.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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/@eslint/eslintrc/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/@eslint/js": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", - "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.15.2", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.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/ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz", @@ -1610,19 +1552,6 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.52.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.2.tgz", @@ -1993,13 +1922,6 @@ "dev": true, "license": "MIT" }, - "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==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/mdast": { "version": "3.0.15", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", @@ -2173,29 +2095,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "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==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -2251,13 +2150,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", - "dev": true, - "license": "Python-2.0" - }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", @@ -2555,16 +2447,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/ccount": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", @@ -3005,13 +2887,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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/default-browser": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", @@ -3625,168 +3500,6 @@ "source-map": "~0.6.1" } }, - "node_modules/eslint": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", - "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.1", - "@eslint/core": "^0.15.2", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.36.0", - "@eslint/plugin-kit": "^0.3.5", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.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", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", - "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "funding": { - "url": "https://opencollective.com/eslint-config-prettier" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", - "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.7" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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/eslint/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/esm": { "version": "3.2.25", "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", @@ -3797,24 +3510,6 @@ "node": ">=6" } }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -3828,32 +3523,6 @@ "node": ">=4" } }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "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==", - "dev": true, - "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", @@ -3990,34 +3659,6 @@ ], "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.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==", - "dev": true, - "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/fault": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", @@ -4028,79 +3669,28 @@ "format": "^0.2.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "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/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/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" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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==", + "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", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, "engines": { - "node": ">=16" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -4389,32 +3979,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "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/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/globalthis": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", @@ -4706,43 +4270,6 @@ "node": ">=0.10.0" } }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5052,16 +4579,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-finalizationregistry": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", @@ -5107,19 +4624,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-hexadecimal": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", @@ -5537,33 +5041,6 @@ "dev": true, "license": "MIT" }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "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==", - "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": "6.2.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", @@ -5576,16 +5053,6 @@ "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -5595,36 +5062,6 @@ "node": ">=0.10.0" } }, - "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": { - "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/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -6243,13 +5680,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "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/netmask": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", @@ -6465,24 +5895,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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/ora": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/ora/-/ora-9.0.0.tgz", @@ -6572,38 +5984,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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/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/pac-proxy-agent": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", @@ -6645,19 +6025,6 @@ "dev": true, "license": "BlueOak-1.0.0" }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/parse-entities": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", @@ -6754,16 +6121,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -6903,45 +6260,6 @@ "node": "^10 || ^12 || >=14" } }, - "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": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/protocols": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", @@ -6986,16 +6304,6 @@ "dev": true, "license": "MIT" }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/rc9": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", @@ -7234,16 +6542,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/restore-cursor": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", @@ -7920,19 +7218,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strip-literal": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", @@ -7971,22 +7256,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/synckit": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", - "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.9" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, "node_modules/tape": { "version": "5.9.0", "resolved": "https://registry.npmjs.org/tape/-/tape-5.9.0.tgz", @@ -8183,19 +7452,6 @@ "dev": true, "license": "0BSD" }, - "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/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -8442,16 +7698,6 @@ "dev": true, "license": "MIT" }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/url-join": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", @@ -8833,16 +8079,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -8971,19 +8207,6 @@ "node": ">=12" } }, - "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" - } - }, "node_modules/yoctocolors": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", diff --git a/package.json b/package.json index 9c7447b..31349fa 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,40 @@ { - "name": "aidd", - "version": "2.5.0", - "description": "The standard framework for AI Driven Development.", - "type": "module", - "sideEffects": false, + "author": "ParallelDrive", "bin": { "aidd": "bin/aidd.js" }, - "scripts": { - "release": "node release.js", - "lint": "eslint --fix && echo 'Lint fix complete.'", - "format": "prettier --write . && echo 'Format complete.'", - "format:check": "prettier --check . && echo 'Format check complete.'", - "test": "vitest run && echo 'Test complete.' && npm run -s lint && npm run -s typecheck", - "test:unit": "vitest run --exclude '**/*-e2e.test.js' && echo 'Unit tests complete.' && npm run -s lint && npm run -s typecheck", - "test:e2e": "vitest run **/*-e2e.test.js && echo 'E2E tests complete.'", - "typecheck": "tsc --noEmit && echo 'Type check complete.'", - "check-status": "[ -n \"$(git status --porcelain)\" ] && { echo '❌ Uncommitted changes'; exit 1; } || echo '✅ Git status is clean.'", - "prepare": "husky", - "toc": "doctoc README.md" + "bugs": { + "url": "https://github.com/paralleldrive/aidd/issues" + }, + "dependencies": { + "@paralleldrive/cuid2": "^3.1.0", + "@sinclair/typebox": "^0.34.41", + "chalk": "^4.1.2", + "commander": "^11.1.0", + "error-causes": "^3.0.2", + "fs-extra": "^11.1.1", + "gray-matter": "^4.0.3", + "js-sha3": "^0.9.3" + }, + "description": "The standard framework for AI Driven Development.", + "devDependencies": { + "@biomejs/biome": "2.3.12", + "@vitest/coverage-v8": "^3.2.4", + "doctoc": "^2.2.1", + "husky": "^9.1.7", + "release-it": "^19.0.5", + "riteway": "^9.0.0-rc.1", + "typescript": "^5.9.3", + "vitest": "^3.2.4" }, "exports": { - "./utils": { - "types": "./utils/index.d.ts", - "default": "./utils/index.js" - }, "./server": { "types": "./src/server/index.d.ts", "default": "./src/server/index.js" + }, + "./utils": { + "types": "./utils/index.d.ts", + "default": "./utils/index.js" } }, "files": [ @@ -44,10 +51,7 @@ "CHANGELOG.md", "CONTRIBUTING.md" ], - "repository": { - "type": "git", - "url": "git+https://github.com/paralleldrive/aidd.git" - }, + "homepage": "https://github.com/paralleldrive/aidd#readme", "keywords": [ "ai-driven-development", "aidd", @@ -58,22 +62,8 @@ "prompt-engineering", "ai-orchestration" ], - "author": "ParallelDrive", "license": "MIT", - "bugs": { - "url": "https://github.com/paralleldrive/aidd/issues" - }, - "homepage": "https://github.com/paralleldrive/aidd#readme", - "dependencies": { - "@paralleldrive/cuid2": "^3.1.0", - "@sinclair/typebox": "^0.34.41", - "chalk": "^4.1.2", - "commander": "^11.1.0", - "error-causes": "^3.0.2", - "fs-extra": "^11.1.1", - "gray-matter": "^4.0.3", - "js-sha3": "^0.9.3" - }, + "name": "aidd", "peerDependencies": { "better-auth": "^1.4.5" }, @@ -82,18 +72,24 @@ "optional": true } }, - "devDependencies": { - "@eslint/eslintrc": "^3", - "@vitest/coverage-v8": "^3.2.4", - "doctoc": "^2.2.1", - "eslint": "^9", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-prettier": "^5.5.4", - "husky": "^9.1.7", - "prettier": "^3.6.2", - "release-it": "^19.0.5", - "riteway": "^9.0.0-rc.1", - "typescript": "^5.9.3", - "vitest": "^3.2.4" - } + "repository": { + "type": "git", + "url": "git+https://github.com/paralleldrive/aidd.git" + }, + "scripts": { + "check-status": "[ -n \"$(git status --porcelain)\" ] && { echo '❌ Uncommitted changes'; exit 1; } || echo '✅ Git status is clean.'", + "format": "npx @biomejs/biome format --write . && echo 'Format complete.'", + "format:check": "npx @biomejs/biome check && echo 'Check complete.'", + "lint": "npx @biomejs/biome check --write && echo 'Lint fix complete.'", + "prepare": "husky", + "release": "node release.js", + "test": "vitest run && echo 'Test complete.' && npm run -s lint && npm run -s typecheck", + "test:e2e": "vitest run **/*-e2e.test.js && echo 'E2E tests complete.'", + "test:unit": "vitest run --exclude '**/*-e2e.test.js' && echo 'Unit tests complete.' && npm run -s lint && npm run -s typecheck", + "toc": "doctoc README.md", + "typecheck": "tsc --noEmit && echo 'Type check complete.'" + }, + "sideEffects": false, + "type": "module", + "version": "2.5.0" } diff --git a/release.js b/release.js index a061b57..ae49227 100755 --- a/release.js +++ b/release.js @@ -2,11 +2,9 @@ import { execSync } from "child_process"; import process from "process"; -import { errorCauses, createError } from "error-causes"; +import { createError, errorCauses } from "error-causes"; // Configuration objects (camelCase per javascript.mdc) -const semverTypes = ["major", "minor", "patch"]; - const bumpAliases = { breaking: "major", feature: "minor", @@ -26,10 +24,6 @@ const config = { // Error causes definition using error-causes library const [releaseErrors, handleReleaseErrors] = errorCauses({ - ValidationError: { - code: "VALIDATION_ERROR", - message: "Input validation failed", - }, GitError: { code: "GIT_ERROR", message: "Git operation failed", @@ -38,6 +32,10 @@ const [releaseErrors, handleReleaseErrors] = errorCauses({ code: "RELEASE_IT_ERROR", message: "release-it command failed", }, + ValidationError: { + code: "VALIDATION_ERROR", + message: "Input validation failed", + }, }); const { ValidationError, GitError, ReleaseItError } = releaseErrors; @@ -67,8 +65,8 @@ const getCurrentBranch = () => { } catch (originalError) { throw createError({ ...GitError, - message: "Failed to get current git branch", cause: originalError, + message: "Failed to get current git branch", }); } }; @@ -88,40 +86,40 @@ const runReleaseIt = (semverType) => { try { console.log(`🚀 Starting release with release-it (${semverType})...`); execSync(`npx release-it ${semverType} --ci`, { - stdio: "inherit", env: { ...process.env }, + stdio: "inherit", }); console.log("🎉 Release completed successfully!"); } catch (originalError) { throw createError({ ...ReleaseItError, - message: "release-it command failed", cause: originalError, + message: "release-it command failed", }); } }; // Use error-causes handleErrors pattern const handleError = handleReleaseErrors({ - ValidationError: ({ name, code, message, cause }) => { - console.error(`❌ Validation failed: ${message}`); - console.error("💡 Fix the issue and try again."); - if (cause) console.error(`🔍 Root cause: ${cause.message || cause}`); - process.exit(1); - }, - GitError: ({ name, code, message, cause }) => { + GitError: ({ message, cause }) => { console.error(`❌ Git command failed: ${message}`); console.error("💡 Check your git configuration and network connection."); if (cause?.command) console.error(`📝 Failed command: ${cause.command}`); if (cause?.message) console.error(`🔍 Root cause: ${cause.message}`); process.exit(1); }, - ReleaseItError: ({ name, code, message, cause }) => { + ReleaseItError: ({ message, cause }) => { console.error(`❌ release-it failed: ${message}`); console.error("💡 Check the release-it output above for details."); if (cause?.message) console.error(`🔍 Root cause: ${cause.message}`); process.exit(1); }, + ValidationError: ({ message, cause }) => { + console.error(`❌ Validation failed: ${message}`); + console.error("💡 Fix the issue and try again."); + if (cause) console.error(`🔍 Root cause: ${cause.message || cause}`); + process.exit(1); + }, }); // Simplified release flow using release-it diff --git a/src/server/create-route.js b/src/server/create-route.js index 8475b87..89c4ca5 100644 --- a/src/server/create-route.js +++ b/src/server/create-route.js @@ -59,15 +59,15 @@ const createRoute = const requestId = response.locals?.requestId; const { url, method, headers } = request; console.log({ - time: new Date().toISOString(), body: JSON.stringify(sanitizeBody(request.body)), - query: JSON.stringify(request.query), - method, - headers: JSON.stringify(sanitizeHeaders(headers)), error: true, - url, + headers: JSON.stringify(sanitizeHeaders(headers)), message: e.message, + method, + query: JSON.stringify(request.query), requestId, + time: new Date().toISOString(), + url, }); response.status(500); response.json({ diff --git a/src/server/create-route.test.js b/src/server/create-route.test.js index 380edd8..79f2924 100644 --- a/src/server/create-route.test.js +++ b/src/server/create-route.test.js @@ -1,6 +1,7 @@ -import { describe, test, beforeEach, vi } from "vitest"; import { assert } from "riteway/vitest"; -import { createRoute, convertMiddleware } from "./create-route.js"; +import { describe, test, vi } from "vitest"; + +import { convertMiddleware, createRoute } from "./create-route.js"; describe("createRoute", () => { test("composes middleware in order", async () => { diff --git a/src/server/index.d.ts b/src/server/index.d.ts index baf068f..6ba4149 100644 --- a/src/server/index.d.ts +++ b/src/server/index.d.ts @@ -67,7 +67,10 @@ export interface ErrorResponse { export type Middleware = (context: ServerContext) => Promise; // Route handler type -export type RouteHandler = (request: Request, response: Response) => Promise; +export type RouteHandler = ( + request: Request, + response: Response, +) => Promise; /** * Creates a route handler that composes middleware using asyncPipe @@ -91,7 +94,11 @@ export function createRoute(...middleware: Middleware[]): RouteHandler; * const functionalMiddleware = convertMiddleware(expressMiddleware); */ export function convertMiddleware( - middleware: (req: Request, res: Response, next: () => void) => void | Promise + middleware: ( + req: Request, + res: Response, + next: () => void, + ) => void | Promise, ): Middleware; /** @@ -110,7 +117,7 @@ export function createServer(options?: { // CORS middleware export interface CorsOptions { - allowedOrigins: string | string[]; // Required for security + allowedOrigins: string | string[]; // Required for security allowedHeaders?: string[]; allowedMethods?: string[]; } @@ -151,7 +158,9 @@ export type ConfigLoader = () => Promise>; * config.get('API_KEY'); // => 'abc123' * config.get('MISSING'); // => throws ErrorWithCause */ -export function createConfigObject(configData: Record): ConfigObject; +export function createConfigObject( + configData: Record, +): ConfigObject; /** * Loads configuration from environment variables @@ -160,7 +169,9 @@ export function createConfigObject(configData: Record): ConfigObjec * const config = await loadConfigFromEnv(['DATABASE_URL', 'API_KEY', 'PORT']); * // => { DATABASE_URL: 'postgres://...', API_KEY: 'abc123', PORT: '3000' } */ -export function loadConfigFromEnv(keys?: string[]): Promise>; +export function loadConfigFromEnv( + keys?: string[], +): Promise>; /** * Creates config injection middleware with custom loader @@ -193,7 +204,9 @@ export const withServerError: Middleware; // Auth middleware types export interface BetterAuthInstance { api: { - getSession(options: { headers: Record }): Promise<{ session: Session; user: User } | null>; + getSession(options: { + headers: Record; + }): Promise<{ session: Session; user: User } | null>; }; [key: string]: any; } @@ -246,7 +259,9 @@ export function createWithAuth(options: WithAuthOptions): Middleware; * }); * }); */ -export function createWithOptionalAuth(options: WithOptionalAuthOptions): Middleware; +export function createWithOptionalAuth( + options: WithOptionalAuthOptions, +): Middleware; // Form handling middleware import type { TObject } from "@sinclair/typebox"; @@ -287,7 +302,9 @@ export interface HandleFormOptions { * honeypotField: 'website', * }); */ -export function handleForm(options: HandleFormOptions): Middleware; +export function handleForm( + options: HandleFormOptions, +): Middleware; // CSRF middleware export interface CSRFOptions { diff --git a/src/server/index.js b/src/server/index.js index 8faa184..c3eee0d 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -35,18 +35,18 @@ * export default createRoute(defaultMiddleware, myHandler); */ -export { createRoute, convertMiddleware } from "./create-route.js"; -export { createServer } from "./test-utils.js"; +export { convertMiddleware, createRoute } from "./create-route.js"; export { - createWithCors, - withRequestId, - createWithConfig, createConfigObject, - loadConfigFromEnv, - withServerError, createWithAuth, + createWithConfig, + createWithCors, + createWithCSRF, createWithOptionalAuth, handleForm, - createWithCSRF, + loadConfigFromEnv, withCSRF, + withRequestId, + withServerError, } from "./middleware/index.js"; +export { createServer } from "./test-utils.js"; diff --git a/src/server/middleware/handle-form.js b/src/server/middleware/handle-form.js index d05ec4a..6c1981b 100644 --- a/src/server/middleware/handle-form.js +++ b/src/server/middleware/handle-form.js @@ -79,8 +79,8 @@ const handleForm = ({ // Check honeypot field if configured if (honeypotField && body[honeypotField]) { log(response, { - message: "Form honeypot triggered", form: name, + message: "Form honeypot triggered", requestId: response.locals?.requestId, }); response.status(400); @@ -96,10 +96,10 @@ const handleForm = ({ if (!valid) { const errors = formatErrors(validator.Errors(body)); log(response, { - message: "Form validation failed", + errorCount: errors.length, form: name, + message: "Form validation failed", requestId: response.locals?.requestId, - errorCount: errors.length, }); response.status(400); response.json({ errors }); diff --git a/src/server/middleware/handle-form.test.js b/src/server/middleware/handle-form.test.js index a94d92a..0214914 100644 --- a/src/server/middleware/handle-form.test.js +++ b/src/server/middleware/handle-form.test.js @@ -1,6 +1,7 @@ -import { describe, test, vi } from "vitest"; -import { assert } from "riteway/vitest"; import { Type } from "@sinclair/typebox"; +import { assert } from "riteway/vitest"; +import { describe, test, vi } from "vitest"; + import { handleForm } from "./handle-form.js"; describe("handleForm", () => { diff --git a/src/server/middleware/index.js b/src/server/middleware/index.js index b92a18f..3ac1b54 100644 --- a/src/server/middleware/index.js +++ b/src/server/middleware/index.js @@ -2,14 +2,14 @@ * Server middleware exports */ -export { createWithCors } from "./with-cors.js"; -export { withRequestId } from "./with-request-id.js"; +export { handleForm } from "./handle-form.js"; +export { createWithAuth, createWithOptionalAuth } from "./with-auth.js"; export { - createWithConfig, createConfigObject, + createWithConfig, loadConfigFromEnv, } from "./with-config.js"; -export { withServerError } from "./with-server-error.js"; -export { createWithAuth, createWithOptionalAuth } from "./with-auth.js"; -export { handleForm } from "./handle-form.js"; +export { createWithCors } from "./with-cors.js"; export { createWithCSRF, withCSRF } from "./with-csrf.js"; +export { withRequestId } from "./with-request-id.js"; +export { withServerError } from "./with-server-error.js"; diff --git a/src/server/middleware/with-auth.js b/src/server/middleware/with-auth.js index 72e62fa..26e12e6 100644 --- a/src/server/middleware/with-auth.js +++ b/src/server/middleware/with-auth.js @@ -43,9 +43,9 @@ const createWithAuth = ({ } = {}) => { if (!auth) { throw createError({ - name: "ValidationError", - message: "auth is required. Pass your better-auth instance.", code: "MISSING_AUTH_INSTANCE", + message: "auth is required. Pass your better-auth instance.", + name: "ValidationError", }); } @@ -60,8 +60,8 @@ const createWithAuth = ({ } response.locals.auth = { - user: result.user, session: result.session, + user: result.user, }; return { request, response }; @@ -90,9 +90,9 @@ const createWithAuth = ({ const createWithOptionalAuth = ({ auth } = {}) => { if (!auth) { throw createError({ - name: "ValidationError", - message: "auth is required. Pass your better-auth instance.", code: "MISSING_AUTH_INSTANCE", + message: "auth is required. Pass your better-auth instance.", + name: "ValidationError", }); } @@ -107,8 +107,8 @@ const createWithOptionalAuth = ({ auth } = {}) => { } response.locals.auth = { - user: result.user, session: result.session, + user: result.user, }; return { request, response }; diff --git a/src/server/middleware/with-auth.test.js b/src/server/middleware/with-auth.test.js index 38218f0..ae8b988 100644 --- a/src/server/middleware/with-auth.test.js +++ b/src/server/middleware/with-auth.test.js @@ -1,7 +1,8 @@ -import { describe, test, vi } from "vitest"; import { assert } from "riteway/vitest"; -import { createWithAuth, createWithOptionalAuth } from "./with-auth.js"; +import { describe, test, vi } from "vitest"; + import { createServer } from "../test-utils.js"; +import { createWithAuth, createWithOptionalAuth } from "./with-auth.js"; // Mock better-auth instance factory const createMockAuth = ({ diff --git a/src/server/middleware/with-config.js b/src/server/middleware/with-config.js index 26c657c..5270fe7 100644 --- a/src/server/middleware/with-config.js +++ b/src/server/middleware/with-config.js @@ -33,8 +33,8 @@ const createConfigObject = (configData) => ({ get(key) { if (!(key in configData)) { throw createError({ - name: "ConfigurationError", message: `Required configuration key "${key}" is not defined.`, + name: "ConfigurationError", requestedKey: key, }); } diff --git a/src/server/middleware/with-config.test.js b/src/server/middleware/with-config.test.js index 9077ea9..02573b5 100644 --- a/src/server/middleware/with-config.test.js +++ b/src/server/middleware/with-config.test.js @@ -1,11 +1,12 @@ -import { describe, test, beforeEach, afterEach } from "vitest"; import { assert } from "riteway/vitest"; +import { afterEach, beforeEach, describe, test } from "vitest"; + +import { createServer } from "../test-utils.js"; import { + createConfigObject, createWithConfig, loadConfigFromEnv, - createConfigObject, } from "./with-config.js"; -import { createServer } from "../test-utils.js"; describe("createConfigObject", () => { test("returns config object with get() method", () => { diff --git a/src/server/middleware/with-cors.js b/src/server/middleware/with-cors.js index 6c9011a..be67e02 100644 --- a/src/server/middleware/with-cors.js +++ b/src/server/middleware/with-cors.js @@ -49,12 +49,12 @@ const createWithCors = ({ // Security: Require explicit origin configuration if (!allowedOrigins) { throw createError({ - name: "ConfigurationError", + code: "MISSING_ALLOWED_ORIGINS", message: "CORS configuration error: allowedOrigins is required. " + 'Specify allowed origins array, a single origin string, or "*" for public APIs. ' + "For same-origin only, omit CORS middleware from your route.", - code: "MISSING_ALLOWED_ORIGINS", + name: "ConfigurationError", }); } diff --git a/src/server/middleware/with-cors.test.js b/src/server/middleware/with-cors.test.js index 5ba3e3e..6f72bea 100644 --- a/src/server/middleware/with-cors.test.js +++ b/src/server/middleware/with-cors.test.js @@ -1,7 +1,8 @@ -import { describe, test, vi } from "vitest"; import { assert } from "riteway/vitest"; -import { createWithCors } from "./with-cors.js"; +import { describe, test, vi } from "vitest"; + import { createServer } from "../test-utils.js"; +import { createWithCors } from "./with-cors.js"; describe("createWithCors", () => { test("requires allowedOrigins parameter", async () => { diff --git a/src/server/middleware/with-csrf.js b/src/server/middleware/with-csrf.js index 9ec6ec5..0e54405 100644 --- a/src/server/middleware/with-csrf.js +++ b/src/server/middleware/with-csrf.js @@ -57,13 +57,13 @@ const rejectRequest = ( { requestId, method, url, hasCookie, hasHeader, hasBody }, ) => { log(response, { + hasBody, + hasCookie, + hasHeader, message: "CSRF validation failed", - requestId, method, + requestId, url, - hasCookie, - hasHeader, - hasBody, }); response.status(403); response.json({ @@ -114,12 +114,12 @@ const createWithCSRF = ({ maxAge = DEFAULT_MAX_AGE } = {}) => { !tokensMatch(cookieToken, submittedToken) ) { rejectRequest(response, { - requestId: response.locals?.requestId, - method: request.method, - url: request.url, + hasBody: Boolean(bodyToken), hasCookie: Boolean(cookieToken), hasHeader: Boolean(headerToken), - hasBody: Boolean(bodyToken), + method: request.method, + requestId: response.locals?.requestId, + url: request.url, }); return { request, response }; } diff --git a/src/server/middleware/with-csrf.test.js b/src/server/middleware/with-csrf.test.js index 084c7eb..732e0f1 100644 --- a/src/server/middleware/with-csrf.test.js +++ b/src/server/middleware/with-csrf.test.js @@ -1,9 +1,10 @@ -import { describe, test, vi } from "vitest"; -import { assert } from "riteway/vitest"; import { Type } from "@sinclair/typebox"; -import { withCSRF } from "./with-csrf.js"; -import { handleForm } from "./handle-form.js"; +import { assert } from "riteway/vitest"; +import { describe, test, vi } from "vitest"; + import { asyncPipe } from "../../../utils/async-pipe.js"; +import { handleForm } from "./handle-form.js"; +import { withCSRF } from "./with-csrf.js"; describe("withCSRF", () => { // Req 1: GET/HEAD/OPTIONS sets token cookie and response.locals.csrfToken diff --git a/src/server/middleware/with-request-id.test.js b/src/server/middleware/with-request-id.test.js index 3dea6f6..a0c391d 100644 --- a/src/server/middleware/with-request-id.test.js +++ b/src/server/middleware/with-request-id.test.js @@ -1,8 +1,9 @@ -import { describe, test } from "vitest"; -import { assert } from "riteway/vitest"; import { isCuid } from "@paralleldrive/cuid2"; -import { withRequestId } from "./with-request-id.js"; +import { assert } from "riteway/vitest"; +import { describe, test } from "vitest"; + import { createServer } from "../test-utils.js"; +import { withRequestId } from "./with-request-id.js"; describe("withRequestId", () => { test("attaches requestId to response.locals", async () => { diff --git a/src/server/middleware/with-server-error.js b/src/server/middleware/with-server-error.js index 9c7af17..03cd24b 100644 --- a/src/server/middleware/with-server-error.js +++ b/src/server/middleware/with-server-error.js @@ -12,8 +12,8 @@ const appendServerError = (response) => { } = {}) => ({ error: { message, - status, requestId, + status, }, }); return response; diff --git a/src/server/middleware/with-server-error.test.js b/src/server/middleware/with-server-error.test.js index dfec073..7668b25 100644 --- a/src/server/middleware/with-server-error.test.js +++ b/src/server/middleware/with-server-error.test.js @@ -1,7 +1,8 @@ -import { describe, test } from "vitest"; import { assert } from "riteway/vitest"; -import { withServerError } from "./with-server-error.js"; +import { describe, test } from "vitest"; + import { createServer } from "../test-utils.js"; +import { withServerError } from "./with-server-error.js"; describe("withServerError", () => { test("attaches serverError function to response.locals", async () => { diff --git a/src/server/test-utils.js b/src/server/test-utils.js index 07e0f94..380e968 100644 --- a/src/server/test-utils.js +++ b/src/server/test-utils.js @@ -16,10 +16,10 @@ const createServer = ({ request = {}, response = {} } = {}) => { return { request, response: { + getHeader: (key) => headers[key], setHeader: (key, value) => { headers[key] = value; }, - getHeader: (key) => headers[key], ...response, }, }; diff --git a/tsconfig.json b/tsconfig.json index 4114496..47aa008 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,25 +1,18 @@ { "compilerOptions": { - "target": "ES2020", - "module": "ES2020", - "lib": ["ES2020"], - "moduleResolution": "node", "allowJs": true, "checkJs": false, - "noEmit": true, - "strict": true, "esModuleInterop": true, - "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true + "lib": ["ES2020"], + "module": "ES2020", + "moduleResolution": "node", + "noEmit": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ES2020" }, - "include": [ - "lib/**/*.d.ts", - "src/**/*.d.ts" - ], - "exclude": [ - "node_modules", - "**/*.test.js" - ] + "exclude": ["node_modules", "**/*.test.js"], + "include": ["lib/**/*.d.ts", "src/**/*.d.ts"] } - diff --git a/utils/index.d.ts b/utils/index.d.ts index 50e60b4..7a84f9e 100644 --- a/utils/index.d.ts +++ b/utils/index.d.ts @@ -15,9 +15,15 @@ * const pipeline = asyncPipe(add1, multiply2); * await pipeline(5); // => 12 */ -export function asyncPipe(...fns: Array<(x: T) => T | Promise>): (x: T) => Promise; -export function asyncPipe(...fns: Array<(x: T | U) => U | Promise>): (x: T) => Promise; -export function asyncPipe(...fns: Array<(x: any) => any>): (x: any) => Promise; +export function asyncPipe( + ...fns: Array<(x: T) => T | Promise> +): (x: T) => Promise; +export function asyncPipe( + ...fns: Array<(x: T | U) => U | Promise> +): (x: T) => Promise; +export function asyncPipe( + ...fns: Array<(x: any) => any> +): (x: any) => Promise; /** * Composes functions from left to right, passing the result of each function @@ -52,4 +58,3 @@ export function pipe(...fns: Array<(x: any) => any>): (x: any) => any; export function compose(...fns: Array<(x: T) => T>): (x: T) => T; export function compose(...fns: Array<(x: T | U) => U>): (x: T) => U; export function compose(...fns: Array<(x: any) => any>): (x: any) => any; - diff --git a/utils/index.js b/utils/index.js index ffbc6f3..f036615 100644 --- a/utils/index.js +++ b/utils/index.js @@ -3,5 +3,5 @@ */ export { asyncPipe } from "./async-pipe.js"; -export { pipe } from "./pipe.js"; export { compose } from "./compose.js"; +export { pipe } from "./pipe.js"; diff --git a/vitest.config.js b/vitest.config.js index 604bbe1..865a317 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -3,11 +3,11 @@ import { defineConfig } from "vitest/config"; export default defineConfig({ test: { - fileParallelism: true, coverage: { + exclude: ["node_modules/**", "tests/**", "*.config.*"], provider: "v8", reporter: ["text", "json", "html"], - exclude: ["node_modules/**", "tests/**", "*.config.*"], }, + fileParallelism: true, }, });