Skip to content

Commit 2ec1bd8

Browse files
committed
chore: init agents.md
1 parent 32412aa commit 2ec1bd8

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

AGENTS.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# rou3
2+
3+
Lightweight, high-performance JavaScript/TypeScript HTTP router. Zero runtime dependencies.
4+
5+
> [!IMPORTANT]
6+
> Keep `AGENTS.md` updated with project status.
7+
8+
## Project Structure
9+
10+
```
11+
src/
12+
index.ts # Public API re-exports
13+
types.ts # TypeScript interfaces & param inference types
14+
context.ts # createRouter() factory
15+
object.ts # NullProtoObj (null-prototype object constructor)
16+
regexp.ts # routeToRegExp() utility
17+
compiler.ts # JIT/AOT compiler (generates optimized match functions)
18+
operations/
19+
add.ts # addRoute() - insert routes into the radix tree
20+
find.ts # findRoute() - single-match lookup
21+
find-all.ts # findAllRoutes() - multi-match lookup
22+
remove.ts # removeRoute() - remove routes from tree
23+
_utils.ts # Shared internal utilities
24+
test/
25+
router.test.ts # Core router tests
26+
find.test.ts # Route matching tests (interpreter vs compiled)
27+
find-all.test.ts # Multi-match tests
28+
regexp.test.ts # RegExp conversion tests
29+
types.test-d.ts # TypeScript type-level tests
30+
bench/ # Performance benchmarks (mitata)
31+
_utils.ts # Test helpers (createRouter, formatTree)
32+
```
33+
34+
## Public API
35+
36+
Two entry points: `rou3` (main) and `rou3/compiler`.
37+
38+
```ts
39+
// rou3
40+
createRouter<T>(options?) -> RouterContext<T>
41+
addRoute(ctx, method, path, data?) -> void
42+
removeRoute(ctx, method, path) -> void
43+
findRoute(ctx, method, path, opts?) -> MatchedRoute<T> | undefined
44+
findAllRoutes(ctx, method, path, opts?) -> MatchedRoute<T>[]
45+
routeToRegExp(route) -> RegExp
46+
47+
// rou3/compiler
48+
compileRouter<T>(router, opts?) -> (method, path) => MatchedRoute<T> | undefined
49+
compileRouterToString(router, functionName?, opts?) -> string
50+
```
51+
52+
## Core Algorithm
53+
54+
**Radix tree** with three node types: **static** (exact match), **param** (`:id`, `*`), **wildcard** (`**`).
55+
56+
### Node structure
57+
58+
```ts
59+
interface Node<T> {
60+
key: string;
61+
static?: Record<string, Node<T>>;
62+
param?: Node<T>;
63+
wildcard?: Node<T>;
64+
hasRegexParam?: boolean;
65+
methods?: Record<string, MethodData<T>[]>;
66+
}
67+
```
68+
69+
### Lookup priority
70+
71+
1. Static child (exact segment match)
72+
2. Param child (single-segment dynamic)
73+
3. Wildcard (multi-segment catch-all)
74+
75+
### Compiler
76+
77+
`compileRouter()` generates an optimized function via `new Function()`:
78+
- Inlines static routes for O(1) lookup
79+
- Unrolls segment checks into `split("/")`-based array access
80+
- Inlines regex patterns for param validation
81+
- Compare interpreter vs compiled output in tests
82+
83+
## Build & Scripts
84+
85+
- **Builder:** `obuild` (config in `build.config.mjs`)
86+
- **Entries:** `src/index.ts`, `src/compiler.ts`
87+
- **Output:** ESM + `.d.mts` declarations
88+
89+
```bash
90+
pnpm build # Build with obuild
91+
pnpm dev # Vitest watch mode
92+
pnpm lint # ESLint + Prettier
93+
pnpm lint:fix # Auto-fix
94+
pnpm test # Full test suite + coverage
95+
pnpm test:types # TypeScript type checking
96+
pnpm bench:node # Benchmarks (node)
97+
pnpm bench:bun # Benchmarks (bun)
98+
pnpm bench:deno # Benchmarks (deno)
99+
```
100+
101+
## Testing
102+
103+
- **Framework:** Vitest (config in `vitest.config.mjs`)
104+
- **Dual validation:** Tests compare `findRoute()` results against `compileRouter()` output
105+
- **Snapshots:** Tree structure and compiled code snapshots
106+
- **Type tests:** `vitest typecheck` via `types.test-d.ts`
107+
- Run a single test: `pnpm vitest run test/<file>.test.ts`
108+
109+
## Code Conventions
110+
111+
- **Performance-first:** `charCodeAt()` over `.startsWith()`, traditional `for` loops, null-prototype objects, `.concat()` over spread
112+
- **Abbreviated hot-path vars:** `m` (method), `p` (path), `s` (segments), `l` (length)
113+
- **Internal files:** Prefixed with `_` (e.g., `_utils.ts`)
114+
- **ESM only**, explicit `.ts` extensions in imports
115+
- **ESLint:** `eslint-config-unjs` with custom overrides
116+
- **Formatter:** Prettier
117+
118+
## Best Practices
119+
120+
### Code Style
121+
122+
- Prefer ESM over CommonJS
123+
- Use explicit extensions (`.ts`/`.js`) in import statements
124+
- For `.json` imports, use `with { "type": "json" }`
125+
- Avoid barrel files (`index.ts` re-exports); import directly from specific modules
126+
- Place non-exported/internal helpers at the end of the file
127+
- For multi-arg functions, use an options object as the second parameter for extensibility
128+
- Split logic across files; avoid long single-file modules (>200 LoC). Use `_*` for naming internal files
129+
130+
### Bug Fix Workflow (Regression-First)
131+
132+
1. **Write the regression test first** — reproduce the exact bug
133+
2. **Run it and confirm it fails** — MUST fail before touching implementation
134+
3. **Fix the implementation** — minimal change
135+
4. **Run the test again** — confirm it passes
136+
5. **Run the broader test suite** — ensure no regressions
137+
138+
Never skip step 2. A regression test that wasn't proven to fail first has no value.
139+
140+
### Git
141+
142+
- **Commits:** Semantic, lower-case (e.g., `perf: ...`, `fix(compiler): ...`), include scope, add short description on second line
143+
- If not on `main`, also `git push` after committing
144+
- Use `gh` CLI for GitHub operations

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

0 commit comments

Comments
 (0)