Skip to content

Commit cfb0dc5

Browse files
committed
Update AGENTS.md
1 parent ac8cbf8 commit cfb0dc5

File tree

1 file changed

+174
-20
lines changed

1 file changed

+174
-20
lines changed

AGENTS.md

Lines changed: 174 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,186 @@
11
# Agent Guidelines
22

3+
Guidelines for AI coding agents working in this repository.
4+
5+
## Project Overview
6+
7+
Small npm package (`@uscreen.de/id-generator`) that generates unique, sortable IDs
8+
using ULID with optional prefixes. Ships raw ES module JavaScript with separate
9+
TypeScript declarations -- no build step.
10+
11+
- **Runtime**: Node.js >= 18
12+
- **Module system**: ES modules (`"type": "module"` in package.json)
13+
- **Package manager**: pnpm (version managed via Corepack, see `packageManager` field)
14+
- **Single production dependency**: `ulid`
15+
316
## Commands
417

5-
- **Test**: `pnpm test` (all tests), `pnpm test:cov` (with coverage), `pnpm test:ci` (CI mode)
6-
- **Lint**: `pnpm lint` (check), `pnpm lint:fix` (fix issues)
7-
- **Pre-publish**: `pnpm prepublishOnly` (runs lint + test)
18+
### Testing
19+
20+
```bash
21+
pnpm test # Run all tests with c8 coverage (spec reporter)
22+
pnpm test:cov # Run tests with HTML + text + lcov coverage reports
23+
pnpm test:ci # Run tests without coverage (CI mode, fast)
24+
```
25+
26+
Run a single test by name using Node.js test runner `--test-name-pattern`:
27+
28+
```bash
29+
node --test --test-name-pattern="with prefix" test.js
30+
```
31+
32+
Run tests matching a file pattern (not applicable here since there is only `test.js`):
33+
34+
```bash
35+
node --test test.js
36+
```
37+
38+
The test runner is Node.js built-in (`node:test`). There is no separate test
39+
framework. Tests live in a single file: `test.js`.
40+
41+
### Linting
42+
43+
```bash
44+
pnpm lint # Check for lint errors
45+
pnpm lint:fix # Auto-fix lint errors (includes formatting)
46+
```
47+
48+
ESLint handles both linting and formatting (no Prettier). Always run `pnpm lint:fix`
49+
after making changes.
50+
51+
### Pre-publish
52+
53+
```bash
54+
pnpm prepublishOnly # Runs lint + test (must pass before npm publish)
55+
```
856

957
## Code Style
1058

11-
- **ESLint**: Uses @antfu/eslint-config with formatters enabled
12-
- **Comma dangle**: Never use trailing commas
13-
- **Curly braces**: Multi-line and consistent
14-
- **Console**: Console statements allowed
15-
- **Imports**: ES modules only (`import`/`export`)
16-
- **Node built-ins**: Use `node:` prefix (e.g., `node:assert/strict`)
59+
### Formatting (enforced by ESLint)
60+
61+
- **No trailing commas** -- `style/comma-dangle: ['error', 'never']`
62+
- **Single quotes** for strings (antfu default)
63+
- **No semicolons** (antfu default)
64+
- **2-space indentation** (antfu default)
65+
- **Curly braces**: required for multi-line blocks, must be consistent within an
66+
if/else chain -- `curly: ['error', 'multi-line', 'consistent']`
67+
- **Console**: `console.log` and similar are allowed (`no-console: off`)
68+
69+
### Imports
70+
71+
- ES modules only -- use `import`/`export`, never `require()`
72+
- Node.js built-ins MUST use the `node:` prefix:
73+
```js
74+
import assert from 'node:assert/strict'
75+
import { describe, test } from 'node:test'
76+
```
77+
- Group imports: external packages first, then local modules, separated by a
78+
blank line:
79+
```js
80+
import { distance } from 'fastest-levenshtein'
81+
82+
import { id } from './index.js'
83+
```
84+
- Always include `.js` extension in relative imports
1785

18-
## Patterns
86+
### Functions
1987

20-
- **Functions**: Export named functions, use arrow functions for internal logic
21-
- **Testing**: Node.js built-in test runner with `describe`/`test` structure
22-
- **Types**: TypeScript declarations in separate `.d.ts` files
23-
- **Dependencies**: Use exact versions, minimal deps (only `ulid` in production)
24-
- **Error handling**: Use `assert` for testing, prefer explicit checks
25-
- **Comments**: JSDoc for public APIs, minimal inline comments
88+
- Use `export const name = (...) => { }` for public API functions (arrow functions)
89+
- The `antfu/top-level-function` rule is disabled -- arrow functions are fine at
90+
top level
91+
- Create aliases by re-exporting: `export const generateId = id`
92+
93+
### Types
94+
95+
- TypeScript declarations live in separate `.d.ts` files (not inline JSDoc types)
96+
- The `.d.ts` files are excluded from ESLint via `eslint.config.js`
97+
- Use `export declare function` syntax in declaration files
98+
- Keep type declarations in sync with the JS implementation
99+
100+
### Naming Conventions
101+
102+
- **Functions/variables**: camelCase (`id`, `generateId`, `monotonicFactory`)
103+
- **Constants**: camelCase (not UPPER_SNAKE_CASE)
104+
- **File names**: lowercase, no special casing (`index.js`, `test.js`)
105+
- **Test descriptions**: descriptive strings starting with the module name
106+
(e.g., `'id generator with prefix'`)
107+
108+
### Comments
109+
110+
- JSDoc `/** */` blocks for public API functions (brief, one-liner descriptions)
111+
- Minimal inline comments -- only when intent is non-obvious
112+
- Section separator comments for logical groupings (e.g., `/** alias exports */`)
113+
114+
### Error Handling
115+
116+
- Use `node:assert/strict` for test assertions (`assert.ok`, `assert.strictEqual`)
117+
- Prefer explicit boolean checks over truthy/falsy where possible
118+
- No try/catch in this codebase -- the library functions are synchronous and
119+
do not throw under normal usage
120+
121+
## Testing Patterns
122+
123+
Tests use Node.js built-in test runner with `describe`/`test` blocks:
124+
125+
```js
126+
import assert from 'node:assert/strict'
127+
import { describe, test } from 'node:test'
128+
129+
describe('feature name', async () => {
130+
test('specific behavior', async () => {
131+
// arrange
132+
const result = someFunction()
133+
// assert
134+
assert.ok(result)
135+
assert.strictEqual(result, expected)
136+
})
137+
})
138+
```
139+
140+
Key patterns observed in `test.js`:
141+
- All test callbacks are `async` functions
142+
- `describe` callback is also `async`
143+
- Use `scheduler.wait(ms)` from `node:timers/promises` for timing-sensitive tests
144+
- Use third-party `fastest-levenshtein` for distance assertions on uniqueness
145+
- Tests verify: correctness, edge cases, sortability, and performance (100k IDs)
26146

27147
## File Structure
28148

29-
- `index.js` - Main implementation (ES modules)
30-
- `index.d.ts` - TypeScript declarations
31-
- `test.js` - All tests using Node.js test runner
32-
- Package manager: pnpm (Node.js 18+)
149+
```
150+
index.js Main implementation (ES module, ~18 lines)
151+
index.d.ts TypeScript type declarations
152+
test.js All tests (Node.js test runner)
153+
eslint.config.js ESLint flat config (antfu + custom rules)
154+
package.json Package metadata, scripts, dependencies
155+
.nvmrc Node.js version for local dev (24)
156+
.github/
157+
workflows/
158+
ci.yml CI pipeline (Node 20/22/24, lint, test, coverage)
159+
codeql.yml GitHub CodeQL security scanning
160+
dependabot.yml Automated dependency updates
161+
```
162+
163+
## CI
164+
165+
- Tests run on Node.js 20, 22, and 24
166+
- Linting runs on Node 20+
167+
- Coverage (c8) generated on Node 22, uploaded to Codecov
168+
- Uses Corepack for pnpm version management
169+
- `pnpm install --frozen-lockfile` in CI (lockfile must be up to date)
170+
171+
## Dependencies Policy
172+
173+
- Keep production dependencies minimal (currently only `ulid`)
174+
- Dev dependencies: ESLint ecosystem (`@antfu/eslint-config`, `eslint`,
175+
`eslint-plugin-format`), coverage (`c8`), test utilities (`fastest-levenshtein`)
176+
- Use caret ranges (`^`) for version specifiers
177+
- Dependabot groups: `dev-dependencies` and `production-dependencies`
178+
179+
## Common Pitfalls
180+
181+
- Do NOT add trailing commas -- the linter will reject them
182+
- Do NOT use `require()` -- this is an ES module package
183+
- Do NOT forget the `node:` prefix on Node.js built-in imports
184+
- Do NOT add semicolons -- antfu config enforces no-semicolons
185+
- Always include `.js` extension in relative import paths
186+
- Run `pnpm lint:fix` before committing to ensure formatting is correct

0 commit comments

Comments
 (0)