Skip to content

Commit 679668d

Browse files
committed
docs(rules): add script file organization and structure conventions
1 parent 8068c75 commit 679668d

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

.claude/rules/scripts.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
description: Script authoring conventions -- file organization, structure, lib/ utilities
3+
paths:
4+
- "scripts/**/*.ts"
5+
alwaysApply: false
6+
---
7+
8+
Scripts live in `scripts/` and are invoked via `bun run scripts/<name>.ts`. Follow the conventions below when adding or modifying scripts.
9+
10+
## File organization
11+
12+
**Top-level scripts** (`scripts/*.ts`) are standalone entry points. Each script handles one task (running tests, creating snapshots, building binaries, signing, etc.) and is wired to a `package.json` script where appropriate.
13+
14+
**`scripts/lib/`** contains shared utilities consumed by multiple top-level scripts. Each file focuses on a single domain (e.g., `op.ts` for 1Password, `npm.ts` for the npm registry, `targets.ts` for platform targets). Move logic into `lib/` only when it is imported by more than one top-level script; otherwise keep it inline.
15+
16+
**Test files** (`scripts/**/*.test.ts`) are co-located next to the module they test and follow the `bun:test` conventions in `rules/testing.md`.
17+
18+
## Script structure
19+
20+
Every top-level script follows this order:
21+
22+
1. **JSDoc header** -- block comment describing what the script does, with `Usage:` examples.
23+
2. **Imports** -- Bun-first APIs preferred (`Bun.spawn`/`Bun.spawnSync` over `child_process`, `Bun.file`/`Bun.write` over `node:fs`). Node.js builtins are fine when Bun has no equivalent (`parseArgs` from `node:util`, `resolve` from `node:path`).
24+
3. **CLI argument parsing** -- `parseArgs` from `node:util` with `strict: true`. All options in a single call near the top. Validate required arguments immediately after, exit early with `process.exit(1)` and a clear error message on invalid input.
25+
4. **Core logic** -- `Bun.spawn` for async subprocesses, `Bun.spawnSync` for synchronous. Check exit codes explicitly. Use `try/finally` when temporary state (config files, temp dirs) needs cleanup.
26+
5. **Exit handling** -- call `process.exit(1)` for expected failures (e.g., "no test files found"). Do not throw unhandled errors for anticipated failure paths.
27+
28+
See `scripts/run-tests.ts` as a reference implementation.
29+
30+
## `lib/` utility conventions
31+
32+
- **No side effects on import.** Importing a `lib/` module must not trigger work (no top-level `await`, no process spawns at module scope).
33+
- **JSDoc header** describing the module's domain and constraints.
34+
- **Export explicit TypeScript types** for structured data (`Target`, etc.) alongside the functions that produce or consume them.
35+
- **Co-locate constants** with the types they relate to (e.g., `SCOPE` and `PKG_PREFIX` live in `targets.ts`).
36+
- **Same Bun-first API preferences** as top-level scripts (`Bun.spawn`, `Bun.$`, `Bun.file`).

0 commit comments

Comments
 (0)