Skip to content

Commit eac5efc

Browse files
authored
chore: add cross-tool AI config files (AGENTS.md, .cursorrules, copilot-instructions.md) (#322)
1 parent c80e368 commit eac5efc

3 files changed

Lines changed: 212 additions & 0 deletions

File tree

.cursorrules

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# react-simplikit Cursor Rules
2+
3+
> Full coding standards with examples: see AGENTS.md
4+
5+
## Project
6+
7+
React hooks/components library. Monorepo: `packages/core` + `packages/mobile`.
8+
9+
## Architecture
10+
11+
Unidirectional layers: `components → hooks → utils → _internal`
12+
Core and mobile are independent packages. No cross-package dependencies.
13+
14+
## Code Style
15+
16+
- `type` over `interface` for type aliases
17+
- Named functions in useEffect: `useEffect(function handleResize() { ... }, [])`
18+
- Named exports only, no default exports
19+
- No `any` — strict TypeScript
20+
- `.ts`/`.tsx` extensions in source imports (tsup converts to `.js`)
21+
- No implicit boolean coercion: `if (value)` → `if (value != null)` (enforced by `strict-boolean-expressions`)
22+
- Nullish checks: `== null` for both null and undefined, `!== undefined` only when distinction matters
23+
- Zero runtime dependencies
24+
- Always return cleanup in useEffect to remove listeners
25+
- Early returns (guard clauses) over nested if-else blocks
26+
- Function declarations use `function` keyword, not arrow: `function toggle(state: boolean) { return !state; }`
27+
- Short inline callbacks (map, filter args) are OK with arrow functions

.github/copilot-instructions.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copilot Instructions for react-simplikit
2+
3+
> Full coding standards with examples: see [AGENTS.md](../../AGENTS.md)
4+
5+
## Quick Reference
6+
7+
- Monorepo: `packages/core` (react-simplikit) + `packages/mobile` (@react-simplikit/mobile)
8+
- Architecture: `components → hooks → utils → _internal` (unidirectional, no circular imports)
9+
- Core and mobile are independent packages — no cross-package dependencies
10+
11+
## Code Style Rules
12+
13+
- Use `type` not `interface` for type aliases
14+
- Named functions in useEffect: `useEffect(function handleResize() { ... }, [])`
15+
- No default exports — named exports only
16+
- No `any` types — strict TypeScript
17+
- Use `.ts`/`.tsx` extensions in source imports (tsup converts to `.js`)
18+
- No implicit boolean coercion: `if (value)``if (value != null)` (enforced by `strict-boolean-expressions`)
19+
- Nullish checks: `== null` for both null and undefined, `!== undefined` only when distinction matters
20+
- Zero runtime dependencies
21+
- Always return cleanup in useEffect to remove listeners
22+
- Prefer early returns (guard clauses) over nested if-else blocks
23+
- Function declarations use `function` keyword, not arrow functions
24+
- Short inline callbacks (map, filter args) are OK with arrow functions

AGENTS.md

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# AGENTS.md
2+
3+
> Tool-agnostic project conventions for AI coding assistants.
4+
> For Claude Code-specific instructions, see [CLAUDE.md](./CLAUDE.md).
5+
6+
## Project Overview
7+
8+
React utility hooks/components library. Monorepo with two packages:
9+
10+
- `react-simplikit` (`packages/core`) — Platform-independent React hooks & components
11+
- `@react-simplikit/mobile` (`packages/mobile`) — Mobile web utilities (viewport, keyboard, layout)
12+
13+
## Architecture
14+
15+
Layer dependency is **unidirectional** — no upward or circular imports:
16+
17+
```
18+
components → hooks → utils → _internal
19+
```
20+
21+
- Components may use hooks, utils, \_internal
22+
- Hooks may use utils, \_internal
23+
- Utils may use \_internal only
24+
- Core and mobile are independent packages — no cross-package dependencies
25+
26+
## File Structure
27+
28+
Each hook/component/util lives in its own folder with co-located docs:
29+
30+
```
31+
src/hooks/useHookName/
32+
├── index.ts # Re-export
33+
├── useHookName.ts # Implementation
34+
├── useHookName.spec.ts # Tests (core) / useHookName.test.ts (mobile)
35+
├── useHookName.ssr.test.ts # SSR safety tests
36+
├── useHookName.md # English docs
37+
└── ko/
38+
└── useHookName.md # Korean docs
39+
```
40+
41+
## Coding Standards
42+
43+
- **`type` over `interface`** — Always use `type` for type aliases
44+
- **Named functions in useEffect**`useEffect(function handleResize() { ... }, [])` not arrow functions
45+
- **No implicit boolean coercion**`if (value)``if (value != null)` (enforced by `strict-boolean-expressions`)
46+
- **Import extensions** — Use `.ts`/`.tsx` extensions in source imports (tsup converts to `.js` for ESM output)
47+
- **Named exports only** — No default exports
48+
- **No `any` types** — Full TypeScript strict mode
49+
- **Zero runtime dependencies**
50+
51+
### Nullish Checks and Control Flow
52+
53+
**Use `== null` for nullish checks** — checks both null and undefined:
54+
55+
```ts
56+
// ✅ Good
57+
if (ref == null) {
58+
continue;
59+
}
60+
items.filter(item => item != null);
61+
62+
// ✅ Use !== undefined only when null/undefined distinction matters
63+
const controlled = valueProp !== undefined;
64+
```
65+
66+
**Prefer early returns (guard clauses)** over nested if-else:
67+
68+
```ts
69+
// ✅ Good — guard clause
70+
function process(value: string | null) {
71+
if (value == null) {
72+
return DEFAULT;
73+
}
74+
return transform(value);
75+
}
76+
77+
// ❌ Bad — nested if-else
78+
function process(value: string | null) {
79+
if (value != null) {
80+
return transform(value);
81+
} else {
82+
return DEFAULT;
83+
}
84+
}
85+
```
86+
87+
**Function declarations use `function` keyword**, arrow functions only for short inline callbacks:
88+
89+
```ts
90+
// ✅ Good — function keyword for declarations
91+
function toggle(state: boolean) {
92+
return !state;
93+
}
94+
95+
// ✅ Good — arrow for inline callbacks
96+
items.filter(item => item != null);
97+
98+
// ❌ Bad — arrow for function declarations
99+
const toggle = (state: boolean) => !state;
100+
```
101+
102+
### SSR-Safe Pattern
103+
104+
All hooks/utils accessing browser APIs must be SSR-safe:
105+
106+
```ts
107+
const [state, setState] = useState(FIXED_INITIAL_VALUE);
108+
useEffect(function syncBrowserState() {
109+
if (isServer()) return;
110+
setState(getBrowserAPI());
111+
}, []);
112+
```
113+
114+
Never initialize state with browser API calls (causes hydration mismatch).
115+
116+
### Hook Return Value Convention
117+
118+
- **Single value**: `useDebounce<T>(value, delay): T`
119+
- **Tuple** (2 items): `useToggle(init): [boolean, () => void]`
120+
- **Object** (3+ items): `usePagination(): { page, nextPage, prevPage }`
121+
122+
## Testing
123+
124+
- **100% coverage mandatory** — Enforced by Vitest coverage threshold
125+
- **SSR tests required** — All hooks accessing browser APIs need `.ssr.test.ts`
126+
- **useEffect cleanup** — Always return cleanup in useEffect to remove listeners
127+
- **SSR test pattern**:
128+
```ts
129+
import { renderHookSSR } from '../../_internal/test-utils/renderHookSSR.tsx';
130+
it('is safe on server side rendering', () => {
131+
const result = renderHookSSR.serverOnly(() => useHookName());
132+
expect(result.current).toBeDefined();
133+
});
134+
```
135+
136+
### Performance Patterns
137+
138+
- Throttle subscriptions at ~16ms (60fps)
139+
- Deduplicate to skip unchanged updates
140+
- Use `startTransition` for non-urgent state updates (React 18+)
141+
142+
## Documentation
143+
144+
- **Bilingual**: English + Korean (co-located in hook folders)
145+
- **JSDoc required**: Every public API must have `@description` + `@example` + `@param` + `@returns`
146+
147+
## Commit Convention
148+
149+
Format: `<type>(<scope>): <description>`
150+
151+
Types: `feat`, `fix`, `docs`, `chore`, `refactor`, `test`
152+
Scope: `core`, `mobile`, or area name
153+
154+
## Commands
155+
156+
```bash
157+
yarn build # Build all packages (tsup)
158+
yarn test # Run tests (Vitest)
159+
yarn fix # Auto-fix lint + format
160+
yarn typecheck # Type check (tsc --noEmit)
161+
```

0 commit comments

Comments
 (0)