Skip to content

Commit b414ac3

Browse files
committed
docs: expand CLAUDE.md with guidance for testing, code style, and build commands
1 parent 4f89035 commit b414ac3

File tree

1 file changed

+56
-24
lines changed

1 file changed

+56
-24
lines changed

CLAUDE.md

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# CLAUDE.md@codebelt/classy-store
1+
# CLAUDE.md
22

3-
Context for Claude Code sessions in this monorepo.
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44

55
## What This Library Is
66

@@ -37,28 +37,6 @@ website/static/ # Served verbatim at site root (llms.txt, llm
3737
examples/ # Framework demo examples
3838
```
3939

40-
## Key Technical Facts
41-
42-
- **Batching:** mutations are coalesced via `queueMicrotask`. Multiple synchronous writes (including array `push` which triggers multiple SET traps) produce a single subscriber notification.
43-
- **Internal state:** stored in a `WeakMap<proxy, StoreInternal>` — never on the user's object. Allows GC when a store is dereferenced.
44-
- **Non-proxyable types:** `Date`, `RegExp`, native `Map`, and native `Set` are treated as opaque values (internal slots can't be intercepted by Proxy). Use `reactiveMap()` and `reactiveSet()` for Map/Set semantics. Replace Date instances entirely to trigger updates.
45-
- **`persist()` exclusions:** getters (detected by walking the prototype chain with `Object.getOwnPropertyDescriptor`) and methods (`typeof value === 'function'`) are automatically excluded from persistence. Only own data properties are saved.
46-
- **Computed memoization:** two layers — the write proxy caches getter results keyed on dependency versions/values; the snapshot layer adds cross-snapshot caching using structural sharing reference equality.
47-
- **Structural sharing:** unchanged sub-trees reuse the previous frozen snapshot reference. This makes `Object.is` comparisons in selectors efficient without `shallowEqual`.
48-
- **Version numbers:** monotonically increasing integers stored per proxy node. Child mutations propagate version bumps up to the root. The snapshot cache is keyed on version — a cache hit is O(1).
49-
50-
## Package Export Entry Points
51-
52-
| Import path | Contents |
53-
|---|---|
54-
| `@codebelt/classy-store` | `createClassyStore`, `snapshot`, `subscribe`, `getVersion`, `shallowEqual`, `reactiveMap`, `reactiveSet`, `Snapshot` type |
55-
| `@codebelt/classy-store/react` | `useStore`, `useLocalStore` |
56-
| `@codebelt/classy-store/vue` | `useStore` (ShallowRef) |
57-
| `@codebelt/classy-store/svelte` | `toSvelteStore` (ClassyReadable) |
58-
| `@codebelt/classy-store/solid` | `useStore` (signal getter) |
59-
| `@codebelt/classy-store/angular` | `injectStore` (Signal) |
60-
| `@codebelt/classy-store/utils` | `persist`, `devtools`, `subscribeKey`, `withHistory` |
61-
6240
## Build & Test Commands
6341

6442
Run from the repo root:
@@ -68,6 +46,10 @@ bun install # Install all workspace dependencies
6846

6947
bun run build # Build all packages (tsdown, outputs to packages/classy-store/dist/)
7048
bun run test # Run all tests (Bun test runner, uses happy-dom for React hook tests)
49+
bun run lint # Check with Biome linter
50+
bun run lint:fix # Auto-fix Biome lint issues
51+
bun run typecheck # TypeScript type check without emit
52+
bun run checkall # lint + test + typecheck (full CI check)
7153

7254
bun run docs:dev # Start Docusaurus dev server at http://localhost:3000/classy-store/
7355
bun run docs:build # Build docs site to website/build/
@@ -78,9 +60,59 @@ Run from `packages/classy-store/`:
7860
```bash
7961
bun run dev # Build in watch mode
8062
bun test # Run tests for this package only
63+
bun test src/core/core.test.ts # Run a single test file
64+
bun test --testNamePattern="batching" core.test.ts # Filter by test name
8165
bun run typecheck # TypeScript type check without emit
8266
```
8367

68+
### Test helper pattern
69+
70+
Because mutations are batched via `queueMicrotask`, tests must flush the microtask queue before asserting on subscriber calls:
71+
72+
```typescript
73+
const flush = () => new Promise<void>((resolve) => setTimeout(resolve, 0));
74+
75+
it('notifies on mutation', async () => {
76+
const store = createClassyStore({ count: 0 });
77+
const cb = mock(() => {});
78+
subscribe(store, cb);
79+
store.count++;
80+
await flush();
81+
expect(cb).toHaveBeenCalledTimes(1);
82+
});
83+
```
84+
85+
## Code Style
86+
87+
Enforced by Biome 2.4.0 (`biome.json` at repo root):
88+
- 2-space indentation, single quotes, no bracket spacing
89+
- `noUnusedImports` is an error
90+
- Style rules enforced as errors: `noImplicitBoolean`, `noInferrableTypes`, `useConsistentCurlyBraces`, `useSingleVarDeclarator`, and others
91+
92+
## Key Technical Facts
93+
94+
- **Batching:** mutations are coalesced via `queueMicrotask`. Multiple synchronous writes (including array `push` which triggers multiple SET traps) produce a single subscriber notification.
95+
- **Internal state:** stored in a `WeakMap<proxy, StoreInternal>` — never on the user's object. Allows GC when a store is dereferenced.
96+
- **Non-proxyable types:** `Date`, `RegExp`, native `Map`, and native `Set` are treated as opaque values (internal slots can't be intercepted by Proxy). Use `reactiveMap()` and `reactiveSet()` for Map/Set semantics. Replace Date instances entirely to trigger updates.
97+
- **Extending reactive types:** a class can opt into deep proxying by setting `static [PROXYABLE] = true` (the `PROXYABLE` symbol is exported from `utils/internal`). `ReactiveMap` and `ReactiveSet` use this.
98+
- **`persist()` exclusions:** getters (detected by walking the prototype chain with `Object.getOwnPropertyDescriptor`) and methods (`typeof value === 'function'`) are automatically excluded from persistence. Only own data properties are saved.
99+
- **Computed memoization:** two layers — the write proxy caches getter results keyed on dependency versions/values; the snapshot layer adds cross-snapshot caching using structural sharing reference equality.
100+
- **Structural sharing:** unchanged sub-trees reuse the previous frozen snapshot reference. This makes `Object.is` comparisons in selectors efficient without `shallowEqual`.
101+
- **Version numbers:** monotonically increasing integers stored per proxy node. Child mutations propagate version bumps up to the root. The snapshot cache is keyed on version — a cache hit is O(1).
102+
- **React auto-tracking:** `useStore(store)` (no selector) wraps the snapshot in a `proxy-compare` tracking proxy. Only properties the component actually reads trigger re-renders. `proxy-compare` is the library's only production dependency.
103+
104+
## Package Export Entry Points
105+
106+
| Import path | Contents |
107+
|---|---|
108+
| `@codebelt/classy-store` | `createClassyStore`, `snapshot`, `subscribe`, `getVersion`, `shallowEqual`, `reactiveMap`, `reactiveSet`, `Snapshot` type |
109+
| `@codebelt/classy-store/react` | `useStore`, `useLocalStore` |
110+
| `@codebelt/classy-store/vue` | `useStore` (ShallowRef) |
111+
| `@codebelt/classy-store/svelte` | `toSvelteStore` (ClassyReadable) |
112+
| `@codebelt/classy-store/solid` | `useStore` (signal getter) |
113+
| `@codebelt/classy-store/angular` | `injectStore` (Signal) |
114+
| `@codebelt/classy-store/utils` | `persist`, `devtools`, `subscribeKey`, `withHistory` |
115+
84116
## LLM Documentation Files
85117

86118
- `website/static/llms.txt` — navigation index (served at `/classy-store/llms.txt`)

0 commit comments

Comments
 (0)