|
9 | 9 | - **Output**: creates `migration/<timestamp>_<slug>/migration.sql` and `snapshot.json`. |
10 | 10 | - **Tests**: migration tests should read the per-folder layout (no `_journal.json`). |
11 | 11 |
|
| 12 | +# Module shape |
| 13 | + |
| 14 | +Do not use `export namespace Foo { ... }` for module organization. It is not |
| 15 | +standard ESM, it prevents tree-shaking, and it breaks Node's native TypeScript |
| 16 | +runner. Use flat top-level exports combined with a self-reexport at the bottom |
| 17 | +of the file: |
| 18 | + |
| 19 | +```ts |
| 20 | +// src/foo/foo.ts |
| 21 | +export interface Interface { ... } |
| 22 | +export class Service extends Context.Service<Service, Interface>()("@opencode/Foo") {} |
| 23 | +export const layer = Layer.effect(Service, ...) |
| 24 | +export const defaultLayer = layer.pipe(...) |
| 25 | + |
| 26 | +export * as Foo from "./foo" |
| 27 | +``` |
| 28 | + |
| 29 | +Consumers import the namespace projection: |
| 30 | + |
| 31 | +```ts |
| 32 | +import { Foo } from "@/foo/foo" |
| 33 | + |
| 34 | +yield * Foo.Service |
| 35 | +Foo.layer |
| 36 | +Foo.defaultLayer |
| 37 | +``` |
| 38 | + |
| 39 | +Namespace-private helpers stay as non-exported top-level declarations in the |
| 40 | +same file — they remain inaccessible to consumers (they are not projected by |
| 41 | +`export * as`) but are usable by the file's own code. |
| 42 | + |
| 43 | +## When the file is an `index.ts` |
| 44 | + |
| 45 | +If the module is `foo/index.ts` (single-namespace directory), use `"."` for |
| 46 | +the self-reexport source rather than `"./index"`: |
| 47 | + |
| 48 | +```ts |
| 49 | +// src/foo/index.ts |
| 50 | +export const thing = ... |
| 51 | + |
| 52 | +export * as Foo from "." |
| 53 | +``` |
| 54 | + |
| 55 | +## Multi-sibling directories |
| 56 | + |
| 57 | +For directories with several independent modules (e.g. `src/session/`, |
| 58 | +`src/config/`), keep each sibling as its own file with its own self-reexport, |
| 59 | +and do not add a barrel `index.ts`. Consumers import the specific sibling: |
| 60 | + |
| 61 | +```ts |
| 62 | +import { SessionRetry } from "@/session/retry" |
| 63 | +import { SessionStatus } from "@/session/status" |
| 64 | +``` |
| 65 | + |
| 66 | +Barrels in multi-sibling directories force every import through the barrel to |
| 67 | +evaluate every sibling, which defeats tree-shaking and slows module load. |
| 68 | + |
12 | 69 | # opencode Effect rules |
13 | 70 |
|
14 | 71 | Use these rules when writing or migrating Effect code. |
|
0 commit comments