|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +Guidelines for AI coding agents working in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +`@studiolambda/query` is a lightweight, isomorphic, framework-agnostic async data management library (SWR-style). It has bindings for React 19+ and Solid.js. |
| 8 | + |
| 9 | +## Build/Lint/Test Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +# Install dependencies |
| 13 | +npm install |
| 14 | + |
| 15 | +# Run all tests |
| 16 | +npm test |
| 17 | + |
| 18 | +# Run tests in watch mode |
| 19 | +npm run dev |
| 20 | + |
| 21 | +# Run a single test file |
| 22 | +npx vitest run src/query/query.test.ts |
| 23 | + |
| 24 | +# Run tests matching a pattern |
| 25 | +npx vitest run -t "can query resources" |
| 26 | + |
| 27 | +# Run with coverage |
| 28 | +npm run test:cover |
| 29 | + |
| 30 | +# Lint |
| 31 | +npm run lint |
| 32 | + |
| 33 | +# Format code |
| 34 | +npm run format |
| 35 | + |
| 36 | +# Check formatting |
| 37 | +npm run format:check |
| 38 | + |
| 39 | +# Build (runs format:check and lint first) |
| 40 | +npm run build |
| 41 | + |
| 42 | +# Build without checks |
| 43 | +npm run build:only |
| 44 | +``` |
| 45 | + |
| 46 | +## Directory Structure |
| 47 | + |
| 48 | +``` |
| 49 | +src/ |
| 50 | + query/ # Core library (framework-agnostic) |
| 51 | + react/ # React bindings |
| 52 | + hooks/ # useQuery, useQueryBasic, etc. |
| 53 | + components/# QueryProvider, QueryPrefetch, etc. |
| 54 | + solid/ # Solid.js bindings (partial) |
| 55 | +``` |
| 56 | + |
| 57 | +## Code Style |
| 58 | + |
| 59 | +### Formatting (Oxfmt) |
| 60 | + |
| 61 | +- Single quotes, no semicolons |
| 62 | +- 2-space indentation (no tabs) |
| 63 | +- 100 character line width |
| 64 | +- Trailing commas: `es5` |
| 65 | +- Always use parentheses in arrow functions: `(x) => x` |
| 66 | +- Configuration: `.oxfmtrc.json` |
| 67 | + |
| 68 | +### Imports |
| 69 | + |
| 70 | +1. External/framework imports first, then internal imports |
| 71 | +2. Use path aliases: `query:index`, `query/react:context`, `query/react:hooks/useQuery` |
| 72 | +3. Use inline `type` keyword for type imports: |
| 73 | + ```typescript |
| 74 | + import { type Options } from 'query:index' |
| 75 | + ``` |
| 76 | +4. Multi-line imports with trailing comma: |
| 77 | + ```typescript |
| 78 | + import { type Caches, type CacheType, type ItemsCacheItem } from 'query:cache' |
| 79 | + ``` |
| 80 | + |
| 81 | +### TypeScript |
| 82 | + |
| 83 | +- Strict mode enabled with `noUnusedLocals`, `noUnusedParameters`, `noImplicitReturns` |
| 84 | +- Use `interface` for object shapes, `type` for unions and function signatures |
| 85 | +- Use `readonly` on interface properties |
| 86 | +- Generic type parameters with defaults: `<T = unknown>` |
| 87 | +- Explicit type assertions when needed: `as T` |
| 88 | + |
| 89 | +### Naming Conventions |
| 90 | + |
| 91 | +| Element | Convention | Example | |
| 92 | +| ------------------ | ----------------------------- | ------------------------------------- | |
| 93 | +| Files (modules) | camelCase | `useQuery.ts`, `cache.ts` | |
| 94 | +| Files (components) | PascalCase | `QueryProvider.tsx` | |
| 95 | +| Test files | `.test.ts`/`.test.tsx` suffix | `query.test.ts` | |
| 96 | +| Functions | camelCase | `createQuery`, `defaultFetcher` | |
| 97 | +| React hooks | `use` prefix | `useQuery`, `useQueryActions` | |
| 98 | +| Types/Interfaces | PascalCase | `Cache`, `Configuration` | |
| 99 | +| Function types | `*Function` suffix | `FetcherFunction`, `MutationFunction` | |
| 100 | +| Props interfaces | `*Props` suffix | `QueryProviderProps` | |
| 101 | + |
| 102 | +### Functions |
| 103 | + |
| 104 | +- Use `function` declarations for named/exported functions (not arrow functions) |
| 105 | +- Use arrow functions only for callbacks and inline functions |
| 106 | +- Use `async/await` for async code |
| 107 | + |
| 108 | +```typescript |
| 109 | +// Correct - regular function for exports |
| 110 | +export function createQuery(options?: Configuration): Query { |
| 111 | + // ... |
| 112 | +} |
| 113 | + |
| 114 | +// Correct - arrow for callbacks |
| 115 | +events.addEventListener(`${event}:${key}`, listener) |
| 116 | +``` |
| 117 | + |
| 118 | +### Exports |
| 119 | + |
| 120 | +- **Named exports only** - never use default exports |
| 121 | +- Use barrel files (`index.ts`) for re-exports |
| 122 | +- Factory pattern for main API: `createQuery()` returns object with methods |
| 123 | + |
| 124 | +### Error Handling |
| 125 | + |
| 126 | +- Simple `throw new Error('message')` for errors |
| 127 | +- Try-catch with event emission pattern for async operations |
| 128 | +- Explicit empty catch `catch(() => {})` when intentionally silencing errors |
| 129 | + |
| 130 | +### Comments |
| 131 | + |
| 132 | +- JSDoc-style block comments for function documentation |
| 133 | +- Inline comments for explaining specific logic |
| 134 | +- Document interface properties with JSDoc |
| 135 | + |
| 136 | +```typescript |
| 137 | +/** |
| 138 | + * Subscribes to a given keyed event. |
| 139 | + */ |
| 140 | +function subscribe<T = unknown>(...) { |
| 141 | + // For the refetching event, we want to immediately return... |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +## Testing |
| 146 | + |
| 147 | +- Test framework: Vitest with happy-dom environment |
| 148 | +- Use `describe.concurrent()` for parallel test execution |
| 149 | +- Destructure `expect` from test context: `it('...', async ({ expect }) => { ... })` |
| 150 | +- React tests use `act()` and `createRoot` |
| 151 | + |
| 152 | +```typescript |
| 153 | +import { describe, it, vi } from 'vitest' |
| 154 | + |
| 155 | +describe.concurrent('feature', function () { |
| 156 | + it('does something', async ({ expect }) => { |
| 157 | + // test code |
| 158 | + expect(result).toBe(expected) |
| 159 | + }) |
| 160 | +}) |
| 161 | +``` |
| 162 | + |
| 163 | +## OxLint |
| 164 | + |
| 165 | +- Configuration: `.oxlintrc.json` |
| 166 | +- React plugin enabled with hooks rules |
| 167 | +- Vitest plugin enabled for test files |
| 168 | +- TypeScript plugin enabled |
| 169 | +- `react-in-jsx-scope` rule disabled (using new JSX transform) |
| 170 | +- Use `// oxlint-disable-next-line` to disable rules inline |
| 171 | + |
| 172 | +## Environment |
| 173 | + |
| 174 | +- Node.js 25+ (see `.nvmrc`) |
| 175 | +- npm 11+ (package manager) |
| 176 | +- TypeScript ~5.9.3 |
| 177 | +- React 19.2+ (peer dependency) |
0 commit comments