|
| 1 | +# Hookable |
| 2 | + |
| 3 | +Lightweight, type-safe, zero-dependency awaitable hook system. |
| 4 | + |
| 5 | +**Important:** Keep AGENTS.md updated with project info. |
| 6 | + |
| 7 | +## Project Overview |
| 8 | + |
| 9 | +- **Type:** ESM-only (`"type": "module"`) |
| 10 | +- **Runtime deps:** None |
| 11 | +- **Bundle size:** Hookable < 3KB, HookableCore < 630B gzipped |
| 12 | + |
| 13 | +Two classes: |
| 14 | + |
| 15 | +- **`Hookable<HooksT>`** β Full-featured: deprecation chains, beforeEach/afterEach spies, serial & parallel execution |
| 16 | +- **`HookableCore<HooksT>`** β Minimal: only `hook()`, `removeHook()`, `callHook()` (~630B) |
| 17 | + |
| 18 | +## Source Structure |
| 19 | + |
| 20 | +``` |
| 21 | +src/ |
| 22 | +βββ index.ts # Public exports |
| 23 | +βββ types.ts # TypeScript type definitions (generics, inference) |
| 24 | +βββ hookable.ts # Hookable & HookableCore classes |
| 25 | +βββ utils.ts # flatHooks, mergeHooks, callers (serial/parallel) |
| 26 | +βββ debugger.ts # createDebugger utility |
| 27 | +``` |
| 28 | + |
| 29 | +## Key Exports |
| 30 | + |
| 31 | +```typescript |
| 32 | +// Classes |
| 33 | +export { Hookable, HookableCore, createHooks } |
| 34 | + |
| 35 | +// Utilities |
| 36 | +export { flatHooks, mergeHooks, parallelCaller, serial, serialCaller } |
| 37 | + |
| 38 | +// Debugger |
| 39 | +export { createDebugger } |
| 40 | +``` |
| 41 | + |
| 42 | +## Development |
| 43 | + |
| 44 | +**Setup:** `eval "$(fnm env --use-on-cd 2>/dev/null)"` then `pnpm install` |
| 45 | + |
| 46 | +| Command | Purpose | |
| 47 | +|---------|---------| |
| 48 | +| `pnpm build` | Build with obuild (esbuild) | |
| 49 | +| `pnpm dev` | Vitest watch mode | |
| 50 | +| `pnpm test` | Lint + vitest with coverage | |
| 51 | +| `pnpm lint` | oxlint + oxfmt check | |
| 52 | +| `pnpm lint:fix` | Auto-fix lint/format | |
| 53 | +| `pnpm test:types` | Type check with tsgo | |
| 54 | +| `pnpm bench` | Benchmarks with mitata | |
| 55 | +| `pnpm release` | test β build β changelogen release | |
| 56 | + |
| 57 | +## Testing |
| 58 | + |
| 59 | +- **Framework:** Vitest |
| 60 | +- **Tests:** `test/hookable.test.ts`, `test/types.test.ts`, `test/debuger.test.ts`, `test/bundle.test.ts` |
| 61 | +- **Run single:** `pnpm vitest run test/hookable.test.ts` |
| 62 | +- Uses `expectTypeOf` for type-level assertions |
| 63 | +- Bundle size enforced in `test/bundle.test.ts` |
| 64 | + |
| 65 | +## Code Conventions |
| 66 | + |
| 67 | +- ESM with explicit `.ts` extensions in imports |
| 68 | +- No barrel files β import directly from modules |
| 69 | +- Internal helpers at end of file |
| 70 | +- Multi-arg functions use options object as 2nd param |
| 71 | +- Constructor binds `hook`, `callHook`, `callHookWith` for safe destructuring |
| 72 | +- Unregister functions nullify references for GC cleanup |
| 73 | +- `console.createTask()` support for DevTools stack traces |
| 74 | + |
| 75 | +## Linting & Formatting |
| 76 | + |
| 77 | +- **Linter:** oxlint (config: `.oxlintrc.json`) |
| 78 | +- **Formatter:** oxfmt (config: `.oxfmtrc.json`) |
| 79 | + |
| 80 | +## Build & Publish |
| 81 | + |
| 82 | +- **Builder:** obuild β `dist/index.mjs` + `dist/index.d.mts` |
| 83 | +- **TypeScript:** ESNext target, NodeNext modules, strict, `isolatedDeclarations` |
| 84 | +- **CI:** GitHub Actions β lint β type check β test + coverage β codecov |
| 85 | +- **Release:** `changelogen --release --publish --push` |
| 86 | +- Only `dist/` published to npm |
0 commit comments