Skip to content

Commit 7a26874

Browse files
authored
Merge pull request #17 from lambda-curry/codex/bun-rules-doc-sync
chore: sync AI rules/docs with Bun testing setup
2 parents 588a8b4 + d894b77 commit 7a26874

36 files changed

+1672
-482
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
description: Project overview and context for react-router-starter
3+
globs: **/*
4+
alwaysApply: true
5+
---
6+
7+
# Project Context
8+
9+
## What This Repo Is
10+
11+
**react-router-starter** is a monorepo starter for React Router 7 apps with best practices: Storybook, @lambdacurry/forms, Bun test + React Testing Library, and shared AI rules.
12+
13+
## Structure
14+
15+
- **apps/todo-app** – Reference app (React Router 7, Vite, Tailwind v4, forms, Storybook, tests).
16+
- **packages/** – Shared packages (e.g. `@todo-starter/ui`, `@todo-starter/utils`) used by apps.
17+
- **ai-rules/** – Source-of-truth AI rules (project context, React Router, Storybook, forms, testing, monorepo, UI).
18+
- **.cursor/rules/** – Generated Cursor rules (do not edit directly).
19+
- **AGENTS.md / CLAUDE.md / GEMINI.md** – Generated agent rules (do not edit directly).
20+
21+
## Issue Tracking (Beads)
22+
23+
Beads is required **only** when running Ralph loops or when a task explicitly comes from Beads. For ad-hoc work, you can skip Beads.
24+
25+
When Beads is in use, follow `.devagent/plugins/ralph/AGENTS.md` and use the CLI:
26+
27+
```bash
28+
bd ready # Find available work
29+
bd show <id> # View issue details
30+
bd update <id> --status in_progress # Claim work
31+
bd update <id> --status closed # Complete work
32+
bd sync # Sync with git
33+
```
34+
35+
## Quality Gates (todo-app)
36+
37+
From `apps/todo-app/package.json`:
38+
39+
- **Test:** `bun run test:run` or `bun run test:ci` (Bun test)
40+
- **Lint:** `npm run lint` (Biome)
41+
- **Typecheck:** `npm run typecheck` (tsc)
42+
- **Build:** `npm run build` (react-router build)
43+
- **Storybook:** `npm run storybook` (dev), `npm run build-storybook` (build)
44+
45+
Run these from `apps/todo-app` or via workspace root scripts if defined.
46+
47+
## Conventions
48+
49+
- **Routing:** File-based routes in `app/routes/`; use loaders/actions and route types.
50+
- **Forms:** @lambdacurry/forms + remix-hook-form + Zod; see `ai-rules/lambda-curry-forms.md`.
51+
- **Tests:** Bun test + React Testing Library; use `renderWithRouter` for router-dependent components; see `apps/todo-app/TESTING.md` and `ai-rules/testing-best-practices.md`.
52+
- **Styling:** Tailwind CSS v4; mobile-first; prefer existing UI components.
53+
54+
## AI Rules Workflow
55+
56+
- **Edit source rules** in `ai-rules/`
57+
- **Generated outputs** in `.generated-ai-rules/` and `.cursor/rules/` are maintained by repository automation
58+
- **Do not edit generated files directly**; change source rules in `ai-rules/`

.cursorrules/lambda-curry-forms.mdc renamed to .cursor/rules/ai-rules-generated-lambda-curry-forms.mdc

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,6 @@ export const action = async ({ request }: ActionFunctionArgs) => {
105105
};
106106
```
107107

108-
## Advanced Patterns
109-
110-
### Conditional Fields
111-
```typescript
112-
const watchAccountType = methods.watch('accountType');
113-
114-
{watchAccountType === 'business' && (
115-
<TextField name="companyName" label="Company Name" />
116-
)}
117-
```
118-
119108
## Available Form Components
120109

121110
### TextField Component
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
description: Monorepo structure, package boundaries, and workspace conventions
3+
globs: **/*
4+
alwaysApply: true
5+
---
6+
7+
# Monorepo Rules
8+
9+
## Package Structure
10+
- `apps/` - Applications (todo-app)
11+
- `packages/` - Shared packages (ui, utils)
12+
- Each package has its own package.json with proper exports
13+
14+
## Workspace Dependencies
15+
- Use `workspace:*` for internal package dependencies
16+
- Keep external dependencies in sync across packages
17+
- Use peerDependencies for shared libraries like React
18+
19+
## Import Patterns
20+
```tsx
21+
// Import from workspace packages
22+
import { Button } from '@todo-starter/ui';
23+
import { cn, type Todo } from '@todo-starter/utils';
24+
25+
// Import from local files
26+
import { TodoItem } from '~/components/todo-item';
27+
import type { Route } from './+types/home';
28+
```
29+
30+
## Package Naming
31+
- Use scoped packages: `@todo-starter/package-name`
32+
- Keep names descriptive and consistent
33+
- Use kebab-case for package names
34+
35+
## Scripts and Tasks
36+
- Define scripts at both root and package level
37+
- Use Turbo for orchestrating build tasks
38+
- Prefer package-specific scripts for development
39+
40+
## TypeScript Configuration
41+
- Use Tailwind CSS v4's CSS-first configuration with `@theme` directive
42+
- Use path mapping for workspace packages
43+
- Keep tsconfig.json files minimal and focused
44+
45+
## Best Practices
46+
- Keep packages focused and single-purpose
47+
- Avoid circular dependencies between packages
48+
- Use proper exports in package.json
49+
- Document package APIs and usage patterns
File renamed without changes.

.cursorrules/storybook.mdc renamed to .cursor/rules/ai-rules-generated-storybook.mdc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ alwaysApply: false
1818
Components that use `Link`, `useNavigate`, `useFetcher`, or `useHref` need router context. Use a global decorator in `preview.tsx`:
1919

2020
```tsx
21+
import type { Preview } from '@storybook/react';
2122
import type { ComponentType } from 'react';
2223
import { createMemoryRouter, RouterProvider } from 'react-router-dom';
2324

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
description: Bun test and React Testing Library patterns for React Router apps
3+
globs: apps/**/*.test.{ts, tsx}, apps/**/*.spec.{ts, tsx}, apps/**/test/**/*
4+
alwaysApply: false
5+
---
6+
7+
# Testing Best Practices
8+
9+
## Stack
10+
11+
- **Runner:** Bun test (`bun:test`) with JSDOM bootstrap in `test/setup.ts` (loaded via `bunfig.toml`)
12+
- **Component/DOM:** React Testing Library
13+
- **Router:** `createMemoryRouter` + `RouterProvider` via shared `renderWithRouter` helper
14+
15+
## Test Layout (todo-app)
16+
17+
| Pattern | Location | Purpose |
18+
|---------------|-----------------------------------|--------|
19+
| Unit | `app/lib/__tests__/*.test.ts` | Pure utilities, helpers |
20+
| Component | `app/components/__tests__/*.test.tsx` | UI with router/context mocking |
21+
| Integration | `app/routes/__tests__/*.integration.test.tsx` | Full route + provider flows |
22+
23+
Shared setup: `test/setup.ts` (jest-dom, RTL cleanup). Shared helpers: `test/test-utils.tsx`.
24+
25+
## Router-Dependent Components
26+
27+
Use `renderWithRouter` for any component that uses `Link`, `useNavigate`, `useFetcher`, or `useHref`:
28+
29+
```tsx
30+
import { renderWithRouter } from '../../../test/test-utils';
31+
32+
it('renders and submits', () => {
33+
renderWithRouter(<MyComponent />);
34+
});
35+
36+
it('renders at /contact', () => {
37+
renderWithRouter(<Page />, { initialEntries: ['/contact'] });
38+
});
39+
```
40+
41+
For full route trees (loaders, nested layouts), use `createTestRouter` or pass `routes` into `renderWithRouter`.
42+
43+
## Integration Tests
44+
45+
Wrap route components with the same providers as the app (e.g. TodoProvider), then assert user flows:
46+
47+
```tsx
48+
import { renderWithRouter } from '../../test/test-utils';
49+
import { TodoProvider } from '../../lib/todo-context';
50+
import Home from '../home';
51+
52+
renderWithRouter(
53+
<TodoProvider>
54+
<Home />
55+
</TodoProvider>
56+
);
57+
// fire events, assert DOM/state
58+
```
59+
60+
## Bun Config (reference)
61+
62+
- **preload:** `test/setup.ts` via `bunfig.toml`
63+
- **jsdom:** initialized in `test/setup.ts` (globals + `@testing-library/jest-dom`)
64+
- **testTimeout:** Bun default is `5000`; adjust with `bun test --timeout <ms>` when needed
65+
66+
## Commands
67+
68+
- `bun run test` – run tests
69+
- `bun run test:watch` – watch mode
70+
- `bun run test:run` / `bun run test:ci` – single run (CI)
71+
72+
## Best Practices
73+
74+
- Prefer `getByRole`, `getByLabelText`, `getByPlaceholderText` over brittle selectors
75+
- Use `jest.fn()` from `bun:test` for callbacks; assert calls and args
76+
- Hoist repeated regex/selectors to describe scope to satisfy lint rules
77+
- Keep tests focused; use multiple `it` blocks instead of one large test
78+
- For forms: test validation, submit behavior, and error display (see lambda-curry-forms rules for FormError)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
description: UI component conventions and shadcn/ui patterns
3+
globs: packages/ui/**/*.tsx, packages/ui/**/*.ts, apps/**/app/**/*.tsx
4+
alwaysApply: true
5+
---
6+
7+
# UI Component Rules
8+
9+
## Component Structure
10+
- Use forwardRef for components that need ref forwarding
11+
- Implement proper TypeScript interfaces
12+
- Use class-variance-authority for variant-based styling
13+
14+
## shadcn/ui Patterns
15+
```tsx
16+
// Component example
17+
import * as React from 'react';
18+
import { cva, type VariantProps } from 'class-variance-authority';
19+
import { cn } from '@todo-starter/utils';
20+
import { Slot } from '@radix-ui/react-slot';
21+
22+
const buttonVariants = cva(
23+
'base-classes',
24+
{
25+
variants: {
26+
variant: {
27+
default: 'default-classes',
28+
destructive: 'destructive-classes'
29+
},
30+
size: {
31+
default: 'default-size',
32+
sm: 'small-size'
33+
}
34+
},
35+
defaultVariants: {
36+
variant: 'default',
37+
size: 'default'
38+
}
39+
}
40+
);
41+
42+
export interface ButtonProps
43+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
44+
VariantProps<typeof buttonVariants> {
45+
asChild?: boolean;
46+
}
47+
48+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
49+
({ className, variant, size, asChild = false, ...props }, ref) => {
50+
const Comp = asChild ? Slot : 'button';
51+
return (
52+
<Comp
53+
className={cn(buttonVariants({ variant, size, className }))}
54+
ref={ref}
55+
{...props}
56+
/>
57+
);
58+
}
59+
);
60+
Button.displayName = 'Button';
61+
```
62+
63+
## Styling Guidelines
64+
- Use Tailwind CSS classes for styling
65+
- Leverage CSS variables for theming
66+
- Use cn() utility for conditional classes
67+
- Follow shadcn/ui color and spacing conventions
68+
69+
## Accessibility
70+
- Include proper ARIA attributes
71+
- Ensure keyboard navigation works
72+
- Use semantic HTML elements
73+
- Test with screen readers
74+
75+
## Component Organization
76+
- Keep components in `packages/ui/src/components/ui/`
77+
- Export all components from main index file
78+
- Group related components together
79+
- Use consistent naming conventions
80+
81+
## Best Practices
82+
- Prefer composition over complex props
83+
- Keep components focused and reusable
84+
- Document component APIs with TypeScript
85+
- Test components in isolation

.cursorrules/00-project-context.mdc

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)