diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..d7f606ac --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +jobs: + quality: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version-file: package.json + + - run: bun install --frozen-lockfile + + - run: bun run typecheck + - run: bun run lint diff --git a/AGENTS.md b/AGENTS.md index 6398b048..3dd87c62 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,9 +20,11 @@ Benchmark execution uses two CLIs: 2. `bun runner/judge.ts` reads generated artifacts, runs LLM judging, and writes results under `results//`. Generation details (`runner/solver/pipeline.ts`): + - `--model` is required and is always used for generation. Judge details (`runner/evaluators/llm/run.ts`): + - `--model` is required and LLM judge always runs against generated artifacts. Key output behavior: diff --git a/bun.lock b/bun.lock index 95c6cc25..e5b8180f 100644 --- a/bun.lock +++ b/bun.lock @@ -24,6 +24,7 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "expo": "^54.0.33", "globals": "^15.14.0", + "lefthook": "^2.1.9", "prettier": "^3.8.1", }, }, @@ -1287,6 +1288,28 @@ "lan-network": ["lan-network@0.1.7", "", { "bin": { "lan-network": "dist/lan-network-cli.js" } }, "sha512-mnIlAEMu4OyEvUNdzco9xpuB9YVcPkQec+QsgycBCtPZvEqWPCDPfbAE4OJMdBBWpZWtpCn1xw9jJYlwjWI5zQ=="], + "lefthook": ["lefthook@2.1.9", "", { "optionalDependencies": { "lefthook-darwin-arm64": "2.1.9", "lefthook-darwin-x64": "2.1.9", "lefthook-freebsd-arm64": "2.1.9", "lefthook-freebsd-x64": "2.1.9", "lefthook-linux-arm64": "2.1.9", "lefthook-linux-x64": "2.1.9", "lefthook-openbsd-arm64": "2.1.9", "lefthook-openbsd-x64": "2.1.9", "lefthook-windows-arm64": "2.1.9", "lefthook-windows-x64": "2.1.9" }, "bin": { "lefthook": "bin/index.js" } }, "sha512-bwDaIOViTktE8kJLf9jP0p+H2/RDTlFFlc43Am2YgUsX22hI6Sq4RbzsrecwzY5y+MHTipOH7WsmWSEniePHWQ=="], + + "lefthook-darwin-arm64": ["lefthook-darwin-arm64@2.1.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-119HryNcvr4nqn0wUIrNPgpMEPn9yMQzEcW/lezRsnb56PCJriJB92+MCySPVcWDxJnZef7o0T3jdnPNiSH7Qg=="], + + "lefthook-darwin-x64": ["lefthook-darwin-x64@2.1.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-dwo5Tke2XcQCM56DGHgFKBfRbJIL6xs2wZ0zG1TUVZgl4t4mQUt6LiZ4V/ZQfYHTZF9qywvXoIlR5N35qOaiVQ=="], + + "lefthook-freebsd-arm64": ["lefthook-freebsd-arm64@2.1.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+09PVap6nl6xsaHch5JLtq7WvIR++U1Q2MzA2ai0M4uB/VP3AqrvKqHw6+9hjyKnIH+HHL83uqi77EAY+LaxLA=="], + + "lefthook-freebsd-x64": ["lefthook-freebsd-x64@2.1.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-8XresjKIYpkE9ARgCtBEZgJZxAU3T4MIqzj4zNy15XRT59I1Us+QdqXTNm+pkZ41Yd2X/nxs2Pkvbq3NWWlIGw=="], + + "lefthook-linux-arm64": ["lefthook-linux-arm64@2.1.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-1oNIQfwrPe6rgU2KcDM3aF6+hpZDCKx1TmawQKpXUY5gVsbZ7MqX0Sk/1lnnWxqPm+kQQ5f6J2dpFWd+4xH8jg=="], + + "lefthook-linux-x64": ["lefthook-linux-x64@2.1.9", "", { "os": "linux", "cpu": "x64" }, "sha512-fT+7Q+BJyGp+CslFQkNXmdFRgyVXsPHPi9NAsDX0a6QOyNnoORByAsvx6zeAKuF5rL3BBgNfho1/v2RuGxGy9w=="], + + "lefthook-openbsd-arm64": ["lefthook-openbsd-arm64@2.1.9", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-4bVuafBk3dddVNo0+3hMbjcJs4mqYAstxpPMmX2ufkudSTYFNIhWoqwuGVQV/SS/xdcOKJAldW4qayAzed2ysw=="], + + "lefthook-openbsd-x64": ["lefthook-openbsd-x64@2.1.9", "", { "os": "openbsd", "cpu": "x64" }, "sha512-PmPoMmLP/wQQWcQ9u2YH86bTZ3UCfBsxuEmVTEyPU2U8R1qSTp5r/Gs3G8cN5Mxo91XB9oBERtF1n+xD3W6aVA=="], + + "lefthook-windows-arm64": ["lefthook-windows-arm64@2.1.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-KphfkBKmwBnmolyrdhIl3lrBaOyTcCgXBT2AB/9OHnEXhOLvv5uTCUkrD4YRAxXPtFKq6UvnapIeoL3GZq0bdA=="], + + "lefthook-windows-x64": ["lefthook-windows-x64@2.1.9", "", { "os": "win32", "cpu": "x64" }, "sha512-2qlUtkJHZ3MyUxgV5XTEmcrIoNZA07iwaquoswAcqv/1MeBFXlD+O+koFRfrzWng2O5WYEbpJnd8tvaYnV8fTA=="], + "leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], diff --git a/docs/adding-new-category.md b/docs/adding-new-category.md index be4fd517..52c445a6 100644 --- a/docs/adding-new-category.md +++ b/docs/adding-new-category.md @@ -5,28 +5,34 @@ This document defines the category-level authoring workflow. ## Workflow 1. Define category scope and baseline libraries. + - Identify the API surface that the category should exercise. - Normalize library naming used in prompts, requirements, and README. 2. Read official docs and recent release notes. + - Capture source links for each core library. - Record dated API shifts that should become requirement constraints. 3. Build category best-practice inventory. + - Convert source guidance into concrete implementation expectations. - Keep entries deterministic and file-verifiable where possible. 4. Derive prompts from best practices. + - Write prompts as forward-looking implementation asks. - Avoid bug-report framing. - Map each prompt to one or more best-practice targets. 5. Define deterministic requirements. + - Express requirements as file-verifiable checks. - Keep requirements atomic and concrete. - Use evidence-backed `MUST NOT` only for deprecations/removals/correctness caveats. 6. Validate diversity and overlap. + - Keep shared subgroup requirements small. - Ensure each eval has implementation-specific constraints. diff --git a/docs/announcing-react-native-evals-article-draft.md b/docs/announcing-react-native-evals-article-draft.md index eee35089..17d1f456 100644 --- a/docs/announcing-react-native-evals-article-draft.md +++ b/docs/announcing-react-native-evals-article-draft.md @@ -7,6 +7,7 @@ - Tone: practical, technical, direct; short sections; concrete claims; end with a clear call to action. Section plan: + 1. What is React Native Evals? 2. Why we made it 3. What models and categories are currently benchmarked @@ -27,12 +28,14 @@ Today we are open-sourcing **React Native Evals**, a benchmark suite designed to React Native Evals is a task-based benchmark for model-generated code. Each eval is a self-contained task in `evals///` with: + - a task prompt (`prompt.md`) - judgeable requirements (`requirements.yaml`) - a baseline app scaffold (`app/`) - a reference implementation (`reference/`) The repository currently includes **136 evals** across seven category groups: + - `animation` (13) - `async-state` (13) - `device-permissions` (24) @@ -52,11 +55,13 @@ React Native Evals focuses on those implementation details so teams can compare ### What models and categories are currently benchmarked? Based on current repository run artifacts (as of **February 27, 2026**), benchmark runs include: + - `gpt-4.1-mini` - `gpt-5.3-codex` - `noop` reference baseline mode (used to validate the judging pipeline without solver generation) Category coverage is currently: + - animation - async state - device permissions @@ -70,6 +75,7 @@ Category coverage is currently: There is no fixed public roadmap list of future category names in-repo yet. Current direction is to: + - continue expanding depth and coverage in the existing seven categories - add new categories through the documented category workflow (`docs/adding-new-category.md`) - prioritize categories with clear, judgeable implementation constraints and strong primary-source API guidance @@ -81,11 +87,13 @@ If you publish this post with a committed roadmap, replace this section with you React Native Evals uses a split pipeline: 1. **Generation stage** (`bun runner/run.ts`) + - discovers evals from `requirements.yaml` - runs a solver model against each eval prompt + baseline files - writes generated outputs plus a manifest 2. **Judge stage** (`bun runner/judge.ts`) + - reads generated outputs - evaluates each declared requirement with an LLM judge - writes per-eval results and run summaries diff --git a/docs/opencode-docker.md b/docs/opencode-docker.md index 0334740a..10a3c8a5 100644 --- a/docs/opencode-docker.md +++ b/docs/opencode-docker.md @@ -6,11 +6,11 @@ The runner starts OpenCode inside Docker for solver and judge model calls. This Each worker session bind-mounts three things into the container: -| Host source | Container path | Mode | Purpose | -| --- | --- | --- | --- | -| Eval workspace directory | `/workspace` | read-write | Files the agent reads and edits | -| Isolated temp dir with copied `~/.local/share/opencode/auth.json` | `/root/.local/share/opencode` (`auth.json` inside) | read-write | OpenCode provider credentials | -| Repo `opencode.json` or `opencode.jsonc` (if present) | `/root/.config/opencode/` | read-only | Provider/model config (no secrets) | +| Host source | Container path | Mode | Purpose | +| ----------------------------------------------------------------- | -------------------------------------------------- | ---------- | ---------------------------------- | +| Eval workspace directory | `/workspace` | read-write | Files the agent reads and edits | +| Isolated temp dir with copied `~/.local/share/opencode/auth.json` | `/root/.local/share/opencode` (`auth.json` inside) | read-write | OpenCode provider credentials | +| Repo `opencode.json` or `opencode.jsonc` (if present) | `/root/.config/opencode/` | read-only | Provider/model config (no secrets) | The host `auth.json` is copied into a per-container temp directory, and that directory is bind-mounted to `/root/.local/share/opencode` so concurrent workers do not share or overwrite the same host file. @@ -129,11 +129,11 @@ bun runner/judge.ts \ ## Related environment variables -| Variable | Default | Effect | -| ------------------------------------ | ---------------------------------------- | ---------------------------------------------------------- | -| `OPENCODE_STREAM_CONTAINER_LOGS` | enabled | Set to `0` to stop streaming `[container]` docker logs | -| `OPENCODE_SERVER_LOG_LEVEL` | `INFO` | Server log level when `--agent-logs` is off | -| `OPENCODE_SERVER_PRINT_LOGS` | off | Set to `1` to enable `--print-logs` without `--agent-logs` | -| `OPENCODE_DOCKER_EXTRA_ENV_PREFIXES` | unset | Comma-separated extra env key prefixes to forward | +| Variable | Default | Effect | +| ------------------------------------ | ------- | ---------------------------------------------------------- | +| `OPENCODE_STREAM_CONTAINER_LOGS` | enabled | Set to `0` to stop streaming `[container]` docker logs | +| `OPENCODE_SERVER_LOG_LEVEL` | `INFO` | Server log level when `--agent-logs` is off | +| `OPENCODE_SERVER_PRINT_LOGS` | off | Set to `1` to enable `--print-logs` without `--agent-logs` | +| `OPENCODE_DOCKER_EXTRA_ENV_PREFIXES` | unset | Comma-separated extra env key prefixes to forward | When a run starts, the runner prints a single line summarizing the effective logging settings (`serve log level`, `agent logs`, `verbose`). diff --git a/docs/testing-your-evals.md b/docs/testing-your-evals.md index 4c297123..4c6a8e72 100644 --- a/docs/testing-your-evals.md +++ b/docs/testing-your-evals.md @@ -1,4 +1,3 @@ - # Testing Your Evals Use this workflow to validate evals end-to-end with split generation and judge CLIs. @@ -38,4 +37,4 @@ Before opening a PR, run: ```bash bun lint -``` \ No newline at end of file +``` diff --git a/evals/animation/01-rn-anim-pressable-scale-with-timing/reference/App.tsx b/evals/animation/01-rn-anim-pressable-scale-with-timing/reference/App.tsx index 62b1c403..f2ea7a0b 100644 --- a/evals/animation/01-rn-anim-pressable-scale-with-timing/reference/App.tsx +++ b/evals/animation/01-rn-anim-pressable-scale-with-timing/reference/App.tsx @@ -27,7 +27,7 @@ export default function App() { progress.value, [0, 1], [COLLAPSED_HEIGHT, EXPANDED_HEIGHT], - Extrapolation.CLAMP, + Extrapolation.CLAMP ), } }) diff --git a/evals/animation/02-rn-anim-spring-toggle-card-height/reference/App.tsx b/evals/animation/02-rn-anim-spring-toggle-card-height/reference/App.tsx index c65f3adf..97adce1a 100644 --- a/evals/animation/02-rn-anim-spring-toggle-card-height/reference/App.tsx +++ b/evals/animation/02-rn-anim-spring-toggle-card-height/reference/App.tsx @@ -51,7 +51,6 @@ export default function App() { style={styles.header} > Shipment details - diff --git a/evals/animation/03-rn-anim-layout-enter-exit-list-items/reference/App.tsx b/evals/animation/03-rn-anim-layout-enter-exit-list-items/reference/App.tsx index d43c61a9..4fee8960 100644 --- a/evals/animation/03-rn-anim-layout-enter-exit-list-items/reference/App.tsx +++ b/evals/animation/03-rn-anim-layout-enter-exit-list-items/reference/App.tsx @@ -23,16 +23,19 @@ export default function App() { const [items, setItems] = useState(INITIAL_ITEMS) const nextId = useRef(INITIAL_ITEMS.length + 1) - const renderItem = useCallback(({ item }: { item: RowItem }) => ( - - {item.label} - - ), []) + const renderItem = useCallback( + ({ item }: { item: RowItem }) => ( + + {item.label} + + ), + [] + ) return ( diff --git a/evals/animation/05-rn-anim-pan-drag-card-with-snap-points/reference/App.tsx b/evals/animation/05-rn-anim-pan-drag-card-with-snap-points/reference/App.tsx index 5b8be7f7..657e5e36 100644 --- a/evals/animation/05-rn-anim-pan-drag-card-with-snap-points/reference/App.tsx +++ b/evals/animation/05-rn-anim-pan-drag-card-with-snap-points/reference/App.tsx @@ -38,7 +38,10 @@ function pickNearestSnapPoint(px: number, py: number): SnapPoint { return nearest } -function pickSnapPointByVelocity(velocityX: number, velocityY: number): SnapPoint { +function pickSnapPointByVelocity( + velocityX: number, + velocityY: number +): SnapPoint { 'worklet' let best = SNAP_POINTS[0] @@ -71,8 +74,7 @@ export default function App() { translateY.value = dragStartY.value + event.translationY }) .onEnd((event) => { - const velocityMag = - Math.sqrt(event.velocityX ** 2 + event.velocityY ** 2) + const velocityMag = Math.sqrt(event.velocityX ** 2 + event.velocityY ** 2) const target = velocityMag >= VELOCITY_THRESHOLD ? pickSnapPointByVelocity(event.velocityX, event.velocityY) diff --git a/evals/animation/12-rn-rngh-scroll-pan-failure-chain/reference/App.tsx b/evals/animation/12-rn-rngh-scroll-pan-failure-chain/reference/App.tsx index e0ba0d7e..079e7dfb 100644 --- a/evals/animation/12-rn-rngh-scroll-pan-failure-chain/reference/App.tsx +++ b/evals/animation/12-rn-rngh-scroll-pan-failure-chain/reference/App.tsx @@ -73,10 +73,10 @@ export default function App() { .onEnd((event) => { 'worklet' const shouldOpen = rowTranslateX.value < ROW_SNAP_OPEN_THRESHOLD - rowTranslateX.value = withSpring( - shouldOpen ? ROW_OPEN_OFFSET : 0, - { ...ROW_SPRING_CONFIG, velocity: event.velocityX } - ) + rowTranslateX.value = withSpring(shouldOpen ? ROW_OPEN_OFFSET : 0, { + ...ROW_SPRING_CONFIG, + velocity: event.velocityX, + }) }) const rowAnimatedStyle = useAnimatedStyle(() => { diff --git a/evals/animation/14-rn-keyboard-controller-aware-scroll-footer/app/App.tsx b/evals/animation/14-rn-keyboard-controller-aware-scroll-footer/app/App.tsx index a28c2386..85468223 100644 --- a/evals/animation/14-rn-keyboard-controller-aware-scroll-footer/app/App.tsx +++ b/evals/animation/14-rn-keyboard-controller-aware-scroll-footer/app/App.tsx @@ -1,4 +1,11 @@ -import { Pressable, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native' +import { + Pressable, + ScrollView, + StyleSheet, + Text, + TextInput, + View, +} from 'react-native' const FIELDS = [ 'First name', @@ -20,7 +27,7 @@ export default function App() { {field} diff --git a/evals/async-state/01-rn-rq-stable-query-key-filters/app/App.tsx b/evals/async-state/01-rn-rq-stable-query-key-filters/app/App.tsx index 086f910f..bf37adca 100644 --- a/evals/async-state/01-rn-rq-stable-query-key-filters/app/App.tsx +++ b/evals/async-state/01-rn-rq-stable-query-key-filters/app/App.tsx @@ -1,11 +1,7 @@ import { useState } from 'react' import { FlatList, Pressable, StyleSheet, Text, View } from 'react-native' -const FILTER_OPTIONS = [ - 'all', - 'smartphones', - 'laptops', -] as const +const FILTER_OPTIONS = ['all', 'smartphones', 'laptops'] as const type Product = { id: number @@ -14,8 +10,8 @@ type Product = { } function TransactionsScreen() { - const [filter, setFilter] = useState('all') - + const [filter, setFilter] = useState<(typeof FILTER_OPTIONS)[number]>('all') + // Update these with real data and logic in later steps const page = 1 const totalPages = 1 @@ -34,7 +30,10 @@ function TransactionsScreen() { onPress={() => { setFilter(candidate) }} - style={[styles.filterButton, isActive && styles.filterButtonActive]} + style={[ + styles.filterButton, + isActive && styles.filterButtonActive, + ]} > = totalPages} onPress={() => {}} - style={[styles.pageButton, page >= totalPages && styles.pageButtonDisabled]} + style={[ + styles.pageButton, + page >= totalPages && styles.pageButtonDisabled, + ]} > Next diff --git a/evals/async-state/01-rn-rq-stable-query-key-filters/prompt.md b/evals/async-state/01-rn-rq-stable-query-key-filters/prompt.md index 8db2b31a..a8fda922 100644 --- a/evals/async-state/01-rn-rq-stable-query-key-filters/prompt.md +++ b/evals/async-state/01-rn-rq-stable-query-key-filters/prompt.md @@ -1,13 +1,16 @@ Build a products screen with TanStack Query where users can change filter tabs (`all`, `smartphones`, `laptops`) and paginate results. Use these endpoint patterns: + - All products: `https://dummyjson.com/products?limit=&skip=` - Category products: `https://dummyjson.com/products/category/?limit=&skip=` Use these response fields: + - `{ "products": [{ "id": number, "title": string, "price": number }], "total": number, "skip": number, "limit": number }` - Map rows from `products` and derive page metadata from `total` `skip` and `limit` Example URLs: + - `https://dummyjson.com/products?limit=10&skip=0` - `https://dummyjson.com/products/category/smartphones?limit=10&skip=0` diff --git a/evals/async-state/01-rn-rq-stable-query-key-filters/reference/App.tsx b/evals/async-state/01-rn-rq-stable-query-key-filters/reference/App.tsx index cee83c34..cc66d07e 100644 --- a/evals/async-state/01-rn-rq-stable-query-key-filters/reference/App.tsx +++ b/evals/async-state/01-rn-rq-stable-query-key-filters/reference/App.tsx @@ -7,13 +7,9 @@ import { useQuery, } from '@tanstack/react-query' -const FILTER_OPTIONS = [ - 'all', - 'smartphones', - 'laptops', -] as const +const FILTER_OPTIONS = ['all', 'smartphones', 'laptops'] as const -type ProductFilter = typeof FILTER_OPTIONS[number] +type ProductFilter = (typeof FILTER_OPTIONS)[number] type Product = { id: number @@ -112,7 +108,10 @@ function ProductsScreen() { onPress={() => { setNextFilter(candidate) }} - style={[styles.filterButton, isActive && styles.filterButtonActive]} + style={[ + styles.filterButton, + isActive && styles.filterButtonActive, + ]} > {isLoading ? Loading… : null} - {isFetching && !isLoading ? Refreshing… : null} + {isFetching && !isLoading ? ( + Refreshing… + ) : null} { setPage((previous) => Math.min(totalPages, previous + 1)) }} - style={[styles.pageButton, page >= totalPages && styles.pageButtonDisabled]} + style={[ + styles.pageButton, + page >= totalPages && styles.pageButtonDisabled, + ]} > Next diff --git a/evals/async-state/02-rn-rq-dependent-query-enabled-gate/app/App.tsx b/evals/async-state/02-rn-rq-dependent-query-enabled-gate/app/App.tsx index 89418f30..2a0e5b35 100644 --- a/evals/async-state/02-rn-rq-dependent-query-enabled-gate/app/App.tsx +++ b/evals/async-state/02-rn-rq-dependent-query-enabled-gate/app/App.tsx @@ -17,9 +17,7 @@ function ProjectsScreen() { } export default function App() { - return ( - - ) + return } const styles = StyleSheet.create({ diff --git a/evals/async-state/02-rn-rq-dependent-query-enabled-gate/prompt.md b/evals/async-state/02-rn-rq-dependent-query-enabled-gate/prompt.md index 48910f5e..61c0e42e 100644 --- a/evals/async-state/02-rn-rq-dependent-query-enabled-gate/prompt.md +++ b/evals/async-state/02-rn-rq-dependent-query-enabled-gate/prompt.md @@ -1,14 +1,17 @@ Build a Profile and Projects screen with TanStack Query where profile data loads first and related rows load after the profile id is available. Use these endpoint patterns: + - Profile: `https://dummyjson.com/users/1` - Related rows: `https://dummyjson.com/todos/user/` Use these response fields: + - Profile response includes `{ "id": number, "firstName": string, "lastName": string }` - Related rows response includes `{ "todos": [{ "id": number, "todo": string, "completed": boolean, "userId": number }] }` - Use profile `id` to request related rows and map row title from `todo` Example URLs: + - `https://dummyjson.com/users/1` - `https://dummyjson.com/todos/user/1` diff --git a/evals/async-state/02-rn-rq-dependent-query-enabled-gate/reference/App.tsx b/evals/async-state/02-rn-rq-dependent-query-enabled-gate/reference/App.tsx index 59a25c95..74dc0531 100644 --- a/evals/async-state/02-rn-rq-dependent-query-enabled-gate/reference/App.tsx +++ b/evals/async-state/02-rn-rq-dependent-query-enabled-gate/reference/App.tsx @@ -95,7 +95,9 @@ function ProjectsScreen() { Projects {!profileId ? ( - Waiting for profile id before fetching projects. + + Waiting for profile id before fetching projects. + ) : null} {projectsQuery.isLoading ? Loading projects… : null} diff --git a/evals/async-state/03-rn-rq-mutation-invalidate-on-success/app/App.tsx b/evals/async-state/03-rn-rq-mutation-invalidate-on-success/app/App.tsx index cb9b8f87..04c74362 100644 --- a/evals/async-state/03-rn-rq-mutation-invalidate-on-success/app/App.tsx +++ b/evals/async-state/03-rn-rq-mutation-invalidate-on-success/app/App.tsx @@ -18,8 +18,8 @@ function ItemsScreen() { @@ -40,9 +40,7 @@ function ItemsScreen() { } export default function App() { - return ( - - ) + return } const styles = StyleSheet.create({ diff --git a/evals/async-state/03-rn-rq-mutation-invalidate-on-success/prompt.md b/evals/async-state/03-rn-rq-mutation-invalidate-on-success/prompt.md index ed36cd2a..2535cf88 100644 --- a/evals/async-state/03-rn-rq-mutation-invalidate-on-success/prompt.md +++ b/evals/async-state/03-rn-rq-mutation-invalidate-on-success/prompt.md @@ -1,17 +1,21 @@ Build an Items screen with TanStack Query where users can load items and create a new item from the composer. Use these endpoint patterns: + - Items list: `https://dummyjson.com/todos?limit=&skip=` - Create item: `https://dummyjson.com/todos/add` Use this create payload: + - `{ "todo": "", "completed": false, "userId": 1 }` Use these response fields: + - List response includes `{ "todos": [{ "id": number, "todo": string, "completed": boolean }] }` - Create response includes `{ "id": number, "todo": string, "completed": boolean, "userId": number }` - Render each row title from `todo` Example URLs: + - `https://dummyjson.com/todos?limit=10&skip=0` - `https://dummyjson.com/todos/add` diff --git a/evals/async-state/03-rn-rq-mutation-invalidate-on-success/reference/App.tsx b/evals/async-state/03-rn-rq-mutation-invalidate-on-success/reference/App.tsx index 3ca7ddc5..c4e9ba0b 100644 --- a/evals/async-state/03-rn-rq-mutation-invalidate-on-success/reference/App.tsx +++ b/evals/async-state/03-rn-rq-mutation-invalidate-on-success/reference/App.tsx @@ -102,8 +102,8 @@ function ItemsScreen() { <View style={styles.composer}> <TextInput onChangeText={setDraft} - placeholder='New item title' - placeholderTextColor='#94a3b8' + placeholder="New item title" + placeholderTextColor="#94a3b8" style={styles.input} value={draft} /> diff --git a/evals/async-state/04-rn-rq-optimistic-update-rollback/app/App.tsx b/evals/async-state/04-rn-rq-optimistic-update-rollback/app/App.tsx index 9f77c8ec..6a9d1ced 100644 --- a/evals/async-state/04-rn-rq-optimistic-update-rollback/app/App.tsx +++ b/evals/async-state/04-rn-rq-optimistic-update-rollback/app/App.tsx @@ -15,26 +15,23 @@ function TodosScreen() { {data.map((todo) => { return ( - <Pressable - key={todo.id} - onPress={() => {}} - style={styles.row} - > - <Text style={[styles.todoText, todo.done && styles.done]}>{todo.title}</Text> + <Pressable key={todo.id} onPress={() => {}} style={styles.row}> + <Text style={[styles.todoText, todo.done && styles.done]}> + {todo.title} + </Text> </Pressable> ) })} - <Text style={styles.error}>Toggle failed. Cache rolled back and revalidated.</Text> + <Text style={styles.error}> + Toggle failed. Cache rolled back and revalidated. + </Text> </View> ) } - export default function App() { - return ( - <TodosScreen /> - ) + return <TodosScreen /> } const styles = StyleSheet.create({ diff --git a/evals/async-state/04-rn-rq-optimistic-update-rollback/prompt.md b/evals/async-state/04-rn-rq-optimistic-update-rollback/prompt.md index a534a73e..2ea589a4 100644 --- a/evals/async-state/04-rn-rq-optimistic-update-rollback/prompt.md +++ b/evals/async-state/04-rn-rq-optimistic-update-rollback/prompt.md @@ -1,17 +1,21 @@ Build a Todo List screen with TanStack Query where tapping a row toggles completion optimistically and rolls back if the update request fails. Use these endpoint patterns: + - Todos list: `https://dummyjson.com/todos?limit=<limit>&skip=<skip>` - Todo update: `https://dummyjson.com/todos/<id>` Use this update payload: + - `{ "completed": <nextDone> }` Use these response fields: + - List response includes `{ "todos": [{ "id": number, "todo": string, "completed": boolean }] }` - Update response includes `{ "id": number, "todo": string, "completed": boolean, "userId": number }` - Map local row shape from `id` `todo` and `completed` Example URLs: + - `https://dummyjson.com/todos?limit=10&skip=0` - `https://dummyjson.com/todos/1` diff --git a/evals/async-state/04-rn-rq-optimistic-update-rollback/reference/App.tsx b/evals/async-state/04-rn-rq-optimistic-update-rollback/reference/App.tsx index 906ac2d9..43103356 100644 --- a/evals/async-state/04-rn-rq-optimistic-update-rollback/reference/App.tsx +++ b/evals/async-state/04-rn-rq-optimistic-update-rollback/reference/App.tsx @@ -132,13 +132,17 @@ function TodosScreen() { onPress={handleTodoPressCallback(todo.id, !todo.done)} style={styles.row} > - <Text style={[styles.todoText, todo.done && styles.done]}>{todo.title}</Text> + <Text style={[styles.todoText, todo.done && styles.done]}> + {todo.title} + </Text> </Pressable> ) })} {toggleMutation.error ? ( - <Text style={styles.error}>Toggle failed. Cache rolled back and revalidated.</Text> + <Text style={styles.error}> + Toggle failed. Cache rolled back and revalidated. + </Text> ) : null} </View> ) diff --git a/evals/async-state/05-rn-zustand-async-action-lifecycle/prompt.md b/evals/async-state/05-rn-zustand-async-action-lifecycle/prompt.md index 0cd88ed3..031b4e18 100644 --- a/evals/async-state/05-rn-zustand-async-action-lifecycle/prompt.md +++ b/evals/async-state/05-rn-zustand-async-action-lifecycle/prompt.md @@ -1,11 +1,14 @@ Using Zustand, build a feed screen with an async action lifecycle state. Use this endpoint pattern: + - Feed items `https://dummyjson.com/todos?limit=<limit>&skip=<skip>` Use this response shape: + - `{ "todos": [{ "id": number, "todo": string, "completed": boolean }] }` - Map feed entries from `todo` Example URL: + - `https://dummyjson.com/todos?limit=3&skip=0` diff --git a/evals/async-state/06-rn-zustand-request-id-stale-response-guard/app/App.tsx b/evals/async-state/06-rn-zustand-request-id-stale-response-guard/app/App.tsx index 2a1b7646..ddf84a86 100644 --- a/evals/async-state/06-rn-zustand-request-id-stale-response-guard/app/App.tsx +++ b/evals/async-state/06-rn-zustand-request-id-stale-response-guard/app/App.tsx @@ -10,8 +10,8 @@ export default function App() { <TextInput onChangeText={setQuery} - placeholder='Type a query' - placeholderTextColor='#94a3b8' + placeholder="Type a query" + placeholderTextColor="#94a3b8" style={styles.input} value={query} /> diff --git a/evals/async-state/06-rn-zustand-request-id-stale-response-guard/prompt.md b/evals/async-state/06-rn-zustand-request-id-stale-response-guard/prompt.md index 68a6efd3..9404b7c0 100644 --- a/evals/async-state/06-rn-zustand-request-id-stale-response-guard/prompt.md +++ b/evals/async-state/06-rn-zustand-request-id-stale-response-guard/prompt.md @@ -1,11 +1,14 @@ Using Zustand, build a Search screen where overlapping requests can race and only the last request wins. Use this endpoint pattern: + - Search results `https://dummyjson.com/products/search?q=<query>&limit=<limit>` Use this response shape: + - `{ "products": [{ "id": number, "title": string }] }` - Build display result from product `title` values Example URL: + - `https://dummyjson.com/products/search?q=phone&limit=3` diff --git a/evals/async-state/06-rn-zustand-request-id-stale-response-guard/reference/App.tsx b/evals/async-state/06-rn-zustand-request-id-stale-response-guard/reference/App.tsx index 58c2f877..df5fb731 100644 --- a/evals/async-state/06-rn-zustand-request-id-stale-response-guard/reference/App.tsx +++ b/evals/async-state/06-rn-zustand-request-id-stale-response-guard/reference/App.tsx @@ -49,7 +49,8 @@ const runSearch = async (nextQuery: string, { set, get }: StoreApi) => { } set({ - result: titles.length > 0 ? titles.join(' • ') : `No results for ${nextQuery}`, + result: + titles.length > 0 ? titles.join(' • ') : `No results for ${nextQuery}`, status: 'ready', }) } @@ -76,8 +77,8 @@ export default function App() { <TextInput onChangeText={setQuery} - placeholder='Type a query' - placeholderTextColor='#94a3b8' + placeholder="Type a query" + placeholderTextColor="#94a3b8" style={styles.input} value={query} /> diff --git a/evals/async-state/07-rn-zustand-persist-async-hydration-gate/prompt.md b/evals/async-state/07-rn-zustand-persist-async-hydration-gate/prompt.md index 45b9504d..917dcd1d 100644 --- a/evals/async-state/07-rn-zustand-persist-async-hydration-gate/prompt.md +++ b/evals/async-state/07-rn-zustand-persist-async-hydration-gate/prompt.md @@ -10,17 +10,21 @@ Show dedicated loading states for session hydration and profile fetch. Show an error message when token or profile fetch fails. Use these endpoint patterns: + - Token `https://dummyjson.com/auth/login` - Profile `https://dummyjson.com/auth/me` Use this token payload: + - `{ "username": "emilys", "password": "emilyspass", "expiresInMins": 30 }` Use these response fields: + - Token response includes `{ "accessToken": string }` and may also include `{ "token": string }` - Profile response includes `{ "firstName": string, "lastName": string }` - Persist token value and build display name from `firstName` and `lastName` Example URLs: + - `https://dummyjson.com/auth/login` - `https://dummyjson.com/auth/me` diff --git a/evals/async-state/09-rn-jotai-async-read-atom-suspense/prompt.md b/evals/async-state/09-rn-jotai-async-read-atom-suspense/prompt.md index 73354e46..152e2182 100644 --- a/evals/async-state/09-rn-jotai-async-read-atom-suspense/prompt.md +++ b/evals/async-state/09-rn-jotai-async-read-atom-suspense/prompt.md @@ -2,11 +2,14 @@ Build a Profile screen where remote data is sourced from a Jotai async read atom Render the atom consumer inside a React `Suspense` boundary with a loading fallback. Use this endpoint pattern: + - Profile `https://dummyjson.com/users/1` Use these response fields: + - `{ "id": number, "firstName": string, "lastName": string }` - Build display name from `firstName` and `lastName` Example URL: + - `https://dummyjson.com/users/1` diff --git a/evals/async-state/10-rn-jotai-loadable-async-atom-no-suspense/app/App.tsx b/evals/async-state/10-rn-jotai-loadable-async-atom-no-suspense/app/App.tsx index c57a7ec8..ef7b7be5 100644 --- a/evals/async-state/10-rn-jotai-loadable-async-atom-no-suspense/app/App.tsx +++ b/evals/async-state/10-rn-jotai-loadable-async-atom-no-suspense/app/App.tsx @@ -4,10 +4,7 @@ export default function App() { return ( <View style={styles.screen}> <Text style={styles.title}>Reports</Text> - <Pressable - onPress={() => {}} - style={styles.button} - > + <Pressable onPress={() => {}} style={styles.button}> <Text style={styles.buttonText}>Reload</Text> </Pressable> </View> diff --git a/evals/async-state/10-rn-jotai-loadable-async-atom-no-suspense/prompt.md b/evals/async-state/10-rn-jotai-loadable-async-atom-no-suspense/prompt.md index 9ab21cf3..5585d0d1 100644 --- a/evals/async-state/10-rn-jotai-loadable-async-atom-no-suspense/prompt.md +++ b/evals/async-state/10-rn-jotai-loadable-async-atom-no-suspense/prompt.md @@ -2,12 +2,15 @@ Build a Reports screen using Jotai without `Suspense`. Keep reports in an async atom, then expose a UI-safe state atom so the screen can render explicit loading data and error branches. Use this endpoint pattern: + - Reports list `https://dummyjson.com/todos?limit=<limit>&skip=<skip>` Use these response fields: + - Success response `{ "todos": [{ "id": number, "todo": string, "completed": boolean }] }` - Map report rows from `id` and `todo` - Non 2xx response should produce the error branch in UI Example URL: + - `https://dummyjson.com/todos?limit=3&skip=0` diff --git a/evals/async-state/11-rn-jotai-async-write-atom-mutation/app/App.tsx b/evals/async-state/11-rn-jotai-async-write-atom-mutation/app/App.tsx index a6d63ba1..a6eb1337 100644 --- a/evals/async-state/11-rn-jotai-async-write-atom-mutation/app/App.tsx +++ b/evals/async-state/11-rn-jotai-async-write-atom-mutation/app/App.tsx @@ -20,15 +20,12 @@ export default function App() { <View style={styles.row}> <TextInput onChangeText={setDraft} - placeholder='Post title' - placeholderTextColor='#94a3b8' + placeholder="Post title" + placeholderTextColor="#94a3b8" style={styles.input} value={draft} /> - <Pressable - onPress={() => {}} - style={styles.button} - > + <Pressable onPress={() => {}} style={styles.button}> <Text style={styles.buttonText}>Save</Text> </Pressable> </View> diff --git a/evals/async-state/11-rn-jotai-async-write-atom-mutation/prompt.md b/evals/async-state/11-rn-jotai-async-write-atom-mutation/prompt.md index 3a9fd2db..af30da97 100644 --- a/evals/async-state/11-rn-jotai-async-write-atom-mutation/prompt.md +++ b/evals/async-state/11-rn-jotai-async-write-atom-mutation/prompt.md @@ -2,14 +2,18 @@ Build a Post Composer with Jotai where submit is handled by an async write atom Use atoms for draft text posts list and submit lifecycle state, and commit the created post back into atom state on success. Use these endpoint patterns: + - Create post `https://dummyjson.com/posts/add` Use this create payload: + - `{ "title": "<title>", "body": "<body>", "userId": 1 }` Use these response fields: + - `{ "id": number, "title": string, "body": string, "userId": number }` - Use `id` and `title` from response when appending created post to local state Example URL: + - `https://dummyjson.com/posts/add` diff --git a/evals/async-state/11-rn-jotai-async-write-atom-mutation/reference/App.tsx b/evals/async-state/11-rn-jotai-async-write-atom-mutation/reference/App.tsx index 363499a3..f504dfaa 100644 --- a/evals/async-state/11-rn-jotai-async-write-atom-mutation/reference/App.tsx +++ b/evals/async-state/11-rn-jotai-async-write-atom-mutation/reference/App.tsx @@ -80,8 +80,8 @@ export default function App() { <View style={styles.row}> <TextInput onChangeText={setDraft} - placeholder='Post title' - placeholderTextColor='#94a3b8' + placeholder="Post title" + placeholderTextColor="#94a3b8" style={styles.input} value={draft} /> diff --git a/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/app/App.tsx b/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/app/App.tsx index 6f722952..c0f9ec1e 100644 --- a/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/app/App.tsx +++ b/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/app/App.tsx @@ -42,7 +42,9 @@ export default function App() { <View style={styles.screen}> <Text style={styles.title}>Preferences</Text> <Text style={styles.meta}>Theme: {preferences.theme}</Text> - <Text style={styles.meta}>Compact mode: {preferences.compact ? 'on' : 'off'}</Text> + <Text style={styles.meta}> + Compact mode: {preferences.compact ? 'on' : 'off'} + </Text> <Pressable onPress={toggleTheme} style={styles.button}> <Text style={styles.buttonText}>Toggle theme</Text> diff --git a/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/prompt.md b/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/prompt.md index 3f5c0558..f1250586 100644 --- a/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/prompt.md +++ b/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/prompt.md @@ -3,11 +3,14 @@ Track hydration completion in atom state and only render preference dependent co After hydration, load and show a profile preview from the API. Use this endpoint pattern after hydration: + - Profile preview `https://dummyjson.com/users/1` Use these response fields: + - `{ "firstName": string, "lastName": string }` - Build profile preview text from `firstName` and `lastName` Example URL: + - `https://dummyjson.com/users/1` diff --git a/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/reference/App.tsx b/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/reference/App.tsx index 797732c8..e504239b 100644 --- a/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/reference/App.tsx +++ b/evals/async-state/12-rn-jotai-atomwithstorage-async-rehydrate-guard/reference/App.tsx @@ -128,9 +128,13 @@ function PreferencesScreen() { <View style={styles.screen}> <Text style={styles.title}>Preferences</Text> <Text style={styles.meta}>Theme: {preferences.theme}</Text> - <Text style={styles.meta}>Compact mode: {preferences.compact ? 'on' : 'off'}</Text> + <Text style={styles.meta}> + Compact mode: {preferences.compact ? 'on' : 'off'} + </Text> <Text style={styles.meta}>Profile status: {profileStatus}</Text> - {profileName ? <Text style={styles.meta}>Profile: {profileName}</Text> : null} + {profileName ? ( + <Text style={styles.meta}>Profile: {profileName}</Text> + ) : null} <Pressable onPress={toggleTheme} style={styles.button}> <Text style={styles.buttonText}>Toggle theme</Text> diff --git a/evals/async-state/13-rn-react-usedeferredvalue-search-stale-indicator/app/App.tsx b/evals/async-state/13-rn-react-usedeferredvalue-search-stale-indicator/app/App.tsx index 39cf6f4c..ac1f2486 100644 --- a/evals/async-state/13-rn-react-usedeferredvalue-search-stale-indicator/app/App.tsx +++ b/evals/async-state/13-rn-react-usedeferredvalue-search-stale-indicator/app/App.tsx @@ -1,19 +1,11 @@ import { useState } from 'react' -import { - FlatList, - StyleSheet, - Text, - TextInput, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, TextInput, View } from 'react-native' export default function App() { const [query, setQuery] = useState('') const renderItem = () => { - return ( - <View style={styles.row}></View> - ) + return <View style={styles.row}></View> } return ( @@ -28,10 +20,7 @@ export default function App() { value={query} /> - <FlatList - data={[]} - renderItem={renderItem} - /> + <FlatList data={[]} renderItem={renderItem} /> </View> ) } diff --git a/evals/async-state/14-rn-rq-react-native-appstate-focus-online-managers/app/App.tsx b/evals/async-state/14-rn-rq-react-native-appstate-focus-online-managers/app/App.tsx index 39aaf094..e6f8bce8 100644 --- a/evals/async-state/14-rn-rq-react-native-appstate-focus-online-managers/app/App.tsx +++ b/evals/async-state/14-rn-rq-react-native-appstate-focus-online-managers/app/App.tsx @@ -1,9 +1,4 @@ -import { - Pressable, - StyleSheet, - Text, - View, -} from 'react-native' +import { Pressable, StyleSheet, Text, View } from 'react-native' import { QueryClient, QueryClientProvider, diff --git a/evals/async-state/14-rn-rq-react-native-appstate-focus-online-managers/reference/App.tsx b/evals/async-state/14-rn-rq-react-native-appstate-focus-online-managers/reference/App.tsx index 4522ee2d..0f504172 100644 --- a/evals/async-state/14-rn-rq-react-native-appstate-focus-online-managers/reference/App.tsx +++ b/evals/async-state/14-rn-rq-react-native-appstate-focus-online-managers/reference/App.tsx @@ -69,7 +69,9 @@ function useReactQueryLifecycleBridge() { const addOnNetInfoChangeListener = () => { return NetInfo.addEventListener((state) => { - const nextOnline = Boolean(state.isConnected && state.isInternetReachable !== false) + const nextOnline = Boolean( + state.isConnected && state.isInternetReachable !== false + ) setIsOnline(nextOnline) onlineManager.setOnline(nextOnline) }) diff --git a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/app/App.tsx b/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/app/App.tsx index 56bc7e6b..cc274570 100644 --- a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/app/App.tsx +++ b/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/app/App.tsx @@ -9,8 +9,13 @@ export default function App() { return ( <View style={styles.screen}> <Text style={styles.title}>Camera Access</Text> - <Text style={styles.subtitle}>Request, retry, and recover camera permission.</Text> - <Pressable style={styles.button} onPress={() => requestCameraPermissionAction()}> + <Text style={styles.subtitle}> + Request, retry, and recover camera permission. + </Text> + <Pressable + style={styles.button} + onPress={() => requestCameraPermissionAction()} + > <Text style={styles.buttonText}>Open</Text> </Pressable> </View> diff --git a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/prompt.md b/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/prompt.md index 6f871527..37fe67e9 100644 --- a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/prompt.md +++ b/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/prompt.md @@ -1 +1 @@ -Build a production-ready camera entry flow with expo-camera. Request camera access only when the user initiates it, handle all permission outcomes with clear retry/recovery UX, keep permission state accurate across app lifecycle transitions (including returning from system settings), and render camera preview only when access is currently available \ No newline at end of file +Build a production-ready camera entry flow with expo-camera. Request camera access only when the user initiates it, handle all permission outcomes with clear retry/recovery UX, keep permission state accurate across app lifecycle transitions (including returning from system settings), and render camera preview only when access is currently available diff --git a/evals/lists/01-rn-flatlist-scroll-to-unread-fixed-rows/app/App.tsx b/evals/lists/01-rn-flatlist-scroll-to-unread-fixed-rows/app/App.tsx index c98aa5e5..5f40c1a4 100644 --- a/evals/lists/01-rn-flatlist-scroll-to-unread-fixed-rows/app/App.tsx +++ b/evals/lists/01-rn-flatlist-scroll-to-unread-fixed-rows/app/App.tsx @@ -9,9 +9,7 @@ const MESSAGES = Array.from({ length: 18 }, (_, index) => ({ })) export default function App() { - return ( - <View style={styles.screen}></View> - ) + return <View style={styles.screen}></View> } const styles = StyleSheet.create({ diff --git a/evals/lists/01-rn-flatlist-scroll-to-unread-fixed-rows/reference/App.tsx b/evals/lists/01-rn-flatlist-scroll-to-unread-fixed-rows/reference/App.tsx index 6cc1e937..1c6f6003 100644 --- a/evals/lists/01-rn-flatlist-scroll-to-unread-fixed-rows/reference/App.tsx +++ b/evals/lists/01-rn-flatlist-scroll-to-unread-fixed-rows/reference/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - FlatList, - StyleSheet, - Text, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' const ROW_HEIGHT = 72 const SEPARATOR_HEIGHT = 10 diff --git a/evals/lists/02-rn-flatlist-basic-contact-list/app/App.tsx b/evals/lists/02-rn-flatlist-basic-contact-list/app/App.tsx index 3dfbd59b..b0dcbede 100644 --- a/evals/lists/02-rn-flatlist-basic-contact-list/app/App.tsx +++ b/evals/lists/02-rn-flatlist-basic-contact-list/app/App.tsx @@ -10,9 +10,7 @@ const CONTACTS = [ ] export default function App() { - return ( - <View style={styles.screen}></View> - ) + return <View style={styles.screen}></View> } const styles = StyleSheet.create({ diff --git a/evals/lists/02-rn-flatlist-basic-contact-list/reference/App.tsx b/evals/lists/02-rn-flatlist-basic-contact-list/reference/App.tsx index 30251c5a..b06b5785 100644 --- a/evals/lists/02-rn-flatlist-basic-contact-list/reference/App.tsx +++ b/evals/lists/02-rn-flatlist-basic-contact-list/reference/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - FlatList, - StyleSheet, - Text, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' const CONTACTS = [ { id: 'contact-1', name: 'Alicia Stone', role: 'Design' }, diff --git a/evals/lists/03-rn-flatlist-two-column-product-grid/app/App.tsx b/evals/lists/03-rn-flatlist-two-column-product-grid/app/App.tsx index e215e253..9a93cb96 100644 --- a/evals/lists/03-rn-flatlist-two-column-product-grid/app/App.tsx +++ b/evals/lists/03-rn-flatlist-two-column-product-grid/app/App.tsx @@ -8,9 +8,7 @@ const PRODUCTS = Array.from({ length: 8 }, (_, index) => ({ })) export default function App() { - return ( - <View style={styles.screen}></View> - ) + return <View style={styles.screen}></View> } const styles = StyleSheet.create({ diff --git a/evals/lists/03-rn-flatlist-two-column-product-grid/reference/App.tsx b/evals/lists/03-rn-flatlist-two-column-product-grid/reference/App.tsx index 001a52c2..e3d5939f 100644 --- a/evals/lists/03-rn-flatlist-two-column-product-grid/reference/App.tsx +++ b/evals/lists/03-rn-flatlist-two-column-product-grid/reference/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - FlatList, - StyleSheet, - Text, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' const PRODUCTS = Array.from({ length: 8 }, (_, index) => ({ id: `product-${index + 1}`, diff --git a/evals/lists/04-rn-flatlist-viewability-impression-tracking/app/App.tsx b/evals/lists/04-rn-flatlist-viewability-impression-tracking/app/App.tsx index e0e2a8c8..4b7d5dbf 100644 --- a/evals/lists/04-rn-flatlist-viewability-impression-tracking/app/App.tsx +++ b/evals/lists/04-rn-flatlist-viewability-impression-tracking/app/App.tsx @@ -7,11 +7,7 @@ const VIDEOS = Array.from({ length: 10 }, (_, index) => ({ creator: index % 2 === 0 ? 'Studio North' : 'Studio South', })) -function VideoCard({ - item, -}: { - item: (typeof VIDEOS)[number] -}) { +function VideoCard({ item }: { item: (typeof VIDEOS)[number] }) { return ( <View style={styles.card}> <View style={styles.thumbnail} /> @@ -22,9 +18,7 @@ function VideoCard({ } export default function App() { - return ( - <View style={styles.screen} /> - ) + return <View style={styles.screen} /> } const styles = StyleSheet.create({ diff --git a/evals/lists/04-rn-flatlist-viewability-impression-tracking/reference/App.tsx b/evals/lists/04-rn-flatlist-viewability-impression-tracking/reference/App.tsx index 1b94e593..89849afa 100644 --- a/evals/lists/04-rn-flatlist-viewability-impression-tracking/reference/App.tsx +++ b/evals/lists/04-rn-flatlist-viewability-impression-tracking/reference/App.tsx @@ -1,11 +1,5 @@ import React, { useState } from 'react' -import { - FlatList, - StyleSheet, - Text, - View, - ViewToken, -} from 'react-native' +import { FlatList, StyleSheet, Text, View, ViewToken } from 'react-native' const VIDEOS = Array.from({ length: 10 }, (_, index) => ({ id: `clip-${index + 1}`, diff --git a/evals/lists/05-rn-flatlist-large-feed-window-tuning/app/App.tsx b/evals/lists/05-rn-flatlist-large-feed-window-tuning/app/App.tsx index 7860f4d6..38440577 100644 --- a/evals/lists/05-rn-flatlist-large-feed-window-tuning/app/App.tsx +++ b/evals/lists/05-rn-flatlist-large-feed-window-tuning/app/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - FlatList, - StyleSheet, - Text, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' const POSTS = Array.from({ length: 80 }, (_, index) => ({ id: `post-${index + 1}`, diff --git a/evals/lists/05-rn-flatlist-large-feed-window-tuning/reference/App.tsx b/evals/lists/05-rn-flatlist-large-feed-window-tuning/reference/App.tsx index 9f7d3598..f831de68 100644 --- a/evals/lists/05-rn-flatlist-large-feed-window-tuning/reference/App.tsx +++ b/evals/lists/05-rn-flatlist-large-feed-window-tuning/reference/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - FlatList, - StyleSheet, - Text, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' const POSTS = Array.from({ length: 80 }, (_, index) => ({ id: `post-${index + 1}`, diff --git a/evals/lists/06-rn-flatlist-pull-to-refresh-feed/app/App.tsx b/evals/lists/06-rn-flatlist-pull-to-refresh-feed/app/App.tsx index 96e28eac..58da7aba 100644 --- a/evals/lists/06-rn-flatlist-pull-to-refresh-feed/app/App.tsx +++ b/evals/lists/06-rn-flatlist-pull-to-refresh-feed/app/App.tsx @@ -1,10 +1,5 @@ import React, { useState } from 'react' -import { - FlatList, - StyleSheet, - Text, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' const INITIAL_POSTS = Array.from({ length: 8 }, (_, index) => ({ id: `post-${index + 1}`, diff --git a/evals/lists/06-rn-flatlist-pull-to-refresh-feed/prompt.md b/evals/lists/06-rn-flatlist-pull-to-refresh-feed/prompt.md index 9a0b0ece..f749e4e2 100644 --- a/evals/lists/06-rn-flatlist-pull-to-refresh-feed/prompt.md +++ b/evals/lists/06-rn-flatlist-pull-to-refresh-feed/prompt.md @@ -1,2 +1,2 @@ -Add pull-to-refresh behavior to the existing `FlatList` feed. +Add pull-to-refresh behavior to the existing `FlatList` feed. Refreshing the list should show refresh state and update the feed data. diff --git a/evals/lists/06-rn-flatlist-pull-to-refresh-feed/reference/App.tsx b/evals/lists/06-rn-flatlist-pull-to-refresh-feed/reference/App.tsx index 8b29d747..213b1c98 100644 --- a/evals/lists/06-rn-flatlist-pull-to-refresh-feed/reference/App.tsx +++ b/evals/lists/06-rn-flatlist-pull-to-refresh-feed/reference/App.tsx @@ -1,10 +1,5 @@ import React, { useState } from 'react' -import { - FlatList, - StyleSheet, - Text, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' const INITIAL_POSTS = Array.from({ length: 8 }, (_, index) => ({ id: `post-${index + 1}`, diff --git a/evals/lists/07-rn-flatlist-to-sectionlist-conversion/app/App.tsx b/evals/lists/07-rn-flatlist-to-sectionlist-conversion/app/App.tsx index 53f8acd8..caccf9c1 100644 --- a/evals/lists/07-rn-flatlist-to-sectionlist-conversion/app/App.tsx +++ b/evals/lists/07-rn-flatlist-to-sectionlist-conversion/app/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - FlatList, - StyleSheet, - Text, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' const CONTACTS = [ { id: 'contact-1', name: 'Alicia Stone', role: 'Design' }, diff --git a/evals/lists/07-rn-flatlist-to-sectionlist-conversion/reference/App.tsx b/evals/lists/07-rn-flatlist-to-sectionlist-conversion/reference/App.tsx index 845315c1..e0608d52 100644 --- a/evals/lists/07-rn-flatlist-to-sectionlist-conversion/reference/App.tsx +++ b/evals/lists/07-rn-flatlist-to-sectionlist-conversion/reference/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - SectionList, - StyleSheet, - Text, - View, -} from 'react-native' +import { SectionList, StyleSheet, Text, View } from 'react-native' const CONTACTS = [ { id: 'contact-1', name: 'Alicia Stone', role: 'Design' }, diff --git a/evals/lists/08-rn-flashlist-basic-list/app/App.tsx b/evals/lists/08-rn-flashlist-basic-list/app/App.tsx index ade4a31d..b9c8d5a2 100644 --- a/evals/lists/08-rn-flashlist-basic-list/app/App.tsx +++ b/evals/lists/08-rn-flashlist-basic-list/app/App.tsx @@ -9,9 +9,7 @@ const ITEMS = [ ] export default function App() { - return ( - <View style={styles.screen} /> - ) + return <View style={styles.screen} /> } const styles = StyleSheet.create({ diff --git a/evals/lists/08-rn-flashlist-basic-list/reference/App.tsx b/evals/lists/08-rn-flashlist-basic-list/reference/App.tsx index 8e3781d8..e8a8269b 100644 --- a/evals/lists/08-rn-flashlist-basic-list/reference/App.tsx +++ b/evals/lists/08-rn-flashlist-basic-list/reference/App.tsx @@ -1,9 +1,5 @@ import React from 'react' -import { - StyleSheet, - Text, - View, -} from 'react-native' +import { StyleSheet, Text, View } from 'react-native' import { FlashList } from '@shopify/flash-list' const ITEMS = [ diff --git a/evals/lists/09-rn-flashlist-horizontal-rail-list-header/app/App.tsx b/evals/lists/09-rn-flashlist-horizontal-rail-list-header/app/App.tsx index 9df41691..19d65d84 100644 --- a/evals/lists/09-rn-flashlist-horizontal-rail-list-header/app/App.tsx +++ b/evals/lists/09-rn-flashlist-horizontal-rail-list-header/app/App.tsx @@ -7,9 +7,7 @@ const VIDEOS = Array.from({ length: 8 }, (_, index) => ({ })) export default function App() { - return ( - <View style={styles.screen} /> - ) + return <View style={styles.screen} /> } const styles = StyleSheet.create({ diff --git a/evals/lists/10-rn-flashlist-horizontal-dynamic-height-header-first-item/app/App.tsx b/evals/lists/10-rn-flashlist-horizontal-dynamic-height-header-first-item/app/App.tsx index c0a370c6..f250ed78 100644 --- a/evals/lists/10-rn-flashlist-horizontal-dynamic-height-header-first-item/app/App.tsx +++ b/evals/lists/10-rn-flashlist-horizontal-dynamic-height-header-first-item/app/App.tsx @@ -9,9 +9,7 @@ const VIDEOS = [ ] export default function App() { - return ( - <View style={styles.screen} /> - ) + return <View style={styles.screen} /> } const styles = StyleSheet.create({ diff --git a/evals/lists/11-rn-flashlist-expandable-cards-layout-state/reference/App.tsx b/evals/lists/11-rn-flashlist-expandable-cards-layout-state/reference/App.tsx index 440c4566..45c76d9b 100644 --- a/evals/lists/11-rn-flashlist-expandable-cards-layout-state/reference/App.tsx +++ b/evals/lists/11-rn-flashlist-expandable-cards-layout-state/reference/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - Pressable, - StyleSheet, - Text, - View, -} from 'react-native' +import { Pressable, StyleSheet, Text, View } from 'react-native' import { FlashList, useLayoutState } from '@shopify/flash-list' const FAQS = [ @@ -25,11 +20,7 @@ const FAQS = [ }, ] -function FaqCard({ - item, -}: { - item: (typeof FAQS)[number] -}) { +function FaqCard({ item }: { item: (typeof FAQS)[number] }) { const [isExpanded, setIsExpanded] = useLayoutState(false) return ( diff --git a/evals/lists/12-rn-flashlist-chat-start-from-bottom/app/App.tsx b/evals/lists/12-rn-flashlist-chat-start-from-bottom/app/App.tsx index 05cef085..f9ecdbb6 100644 --- a/evals/lists/12-rn-flashlist-chat-start-from-bottom/app/App.tsx +++ b/evals/lists/12-rn-flashlist-chat-start-from-bottom/app/App.tsx @@ -7,11 +7,7 @@ const INITIAL_MESSAGES = Array.from({ length: 8 }, (_, index) => ({ text: `Chat message ${index + 1}`, })) -function MessageBubble({ - item, -}: { - item: (typeof INITIAL_MESSAGES)[number] -}) { +function MessageBubble({ item }: { item: (typeof INITIAL_MESSAGES)[number] }) { return ( <View style={styles.bubble}> <Text style={styles.sender}>{item.from}</Text> @@ -21,9 +17,7 @@ function MessageBubble({ } export default function App() { - return ( - <View style={styles.screen} /> - ) + return <View style={styles.screen} /> } const styles = StyleSheet.create({ diff --git a/evals/lists/12-rn-flashlist-chat-start-from-bottom/reference/App.tsx b/evals/lists/12-rn-flashlist-chat-start-from-bottom/reference/App.tsx index 94546293..1cc01141 100644 --- a/evals/lists/12-rn-flashlist-chat-start-from-bottom/reference/App.tsx +++ b/evals/lists/12-rn-flashlist-chat-start-from-bottom/reference/App.tsx @@ -8,11 +8,7 @@ const INITIAL_MESSAGES = Array.from({ length: 8 }, (_, index) => ({ text: `Chat message ${index + 1}`, })) -function MessageBubble({ - item, -}: { - item: (typeof INITIAL_MESSAGES)[number] -}) { +function MessageBubble({ item }: { item: (typeof INITIAL_MESSAGES)[number] }) { return ( <View style={styles.bubble}> <Text style={styles.sender}>{item.from}</Text> diff --git a/evals/lists/13-rn-flashlist-masonry-photo-gallery/app/App.tsx b/evals/lists/13-rn-flashlist-masonry-photo-gallery/app/App.tsx index 471317f2..23931242 100644 --- a/evals/lists/13-rn-flashlist-masonry-photo-gallery/app/App.tsx +++ b/evals/lists/13-rn-flashlist-masonry-photo-gallery/app/App.tsx @@ -11,10 +11,7 @@ const PHOTOS = [ ] export default function App() { - return ( - <View style={styles.screen}> - </View> - ) + return <View style={styles.screen}></View> } const styles = StyleSheet.create({ diff --git a/evals/lists/14-rn-flatlist-to-legendlist-migration/app/App.tsx b/evals/lists/14-rn-flatlist-to-legendlist-migration/app/App.tsx index 5ab730d2..2722a913 100644 --- a/evals/lists/14-rn-flatlist-to-legendlist-migration/app/App.tsx +++ b/evals/lists/14-rn-flatlist-to-legendlist-migration/app/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - FlatList, - StyleSheet, - Text, - View, -} from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' const ITEMS = [ { id: 'item-1', title: 'Shift overview', subtitle: 'Morning operations' }, diff --git a/evals/lists/14-rn-flatlist-to-legendlist-migration/reference/App.tsx b/evals/lists/14-rn-flatlist-to-legendlist-migration/reference/App.tsx index 7c638dba..5b4cb99c 100644 --- a/evals/lists/14-rn-flatlist-to-legendlist-migration/reference/App.tsx +++ b/evals/lists/14-rn-flatlist-to-legendlist-migration/reference/App.tsx @@ -1,9 +1,5 @@ import React from 'react' -import { - StyleSheet, - Text, - View, -} from 'react-native' +import { StyleSheet, Text, View } from 'react-native' import { LegendList } from '@legendapp/list' const ITEMS = [ diff --git a/evals/lists/15-rn-legendlist-sticky-grouped-agenda/app/App.tsx b/evals/lists/15-rn-legendlist-sticky-grouped-agenda/app/App.tsx index 7a963870..13a78a7e 100644 --- a/evals/lists/15-rn-legendlist-sticky-grouped-agenda/app/App.tsx +++ b/evals/lists/15-rn-legendlist-sticky-grouped-agenda/app/App.tsx @@ -9,10 +9,7 @@ const EVENTS = [ ] export default function App() { - return ( - <View style={styles.screen}> - </View> - ) + return <View style={styles.screen}></View> } const styles = StyleSheet.create({ diff --git a/evals/lists/16-rn-legendlist-section-scroll-to-location/reference/App.tsx b/evals/lists/16-rn-legendlist-section-scroll-to-location/reference/App.tsx index 34c45e78..9361b052 100644 --- a/evals/lists/16-rn-legendlist-section-scroll-to-location/reference/App.tsx +++ b/evals/lists/16-rn-legendlist-section-scroll-to-location/reference/App.tsx @@ -1,10 +1,5 @@ import React, { useRef } from 'react' -import { - Pressable, - StyleSheet, - Text, - View, -} from 'react-native' +import { Pressable, StyleSheet, Text, View } from 'react-native' import { SectionList } from '@legendapp/list/section-list' const AGENDA = [ diff --git a/evals/lists/17-rn-legendlist-chat-start-from-bottom/app/App.tsx b/evals/lists/17-rn-legendlist-chat-start-from-bottom/app/App.tsx index ca70da01..5249253c 100644 --- a/evals/lists/17-rn-legendlist-chat-start-from-bottom/app/App.tsx +++ b/evals/lists/17-rn-legendlist-chat-start-from-bottom/app/App.tsx @@ -1,10 +1,5 @@ import React, { useState } from 'react' -import { - Pressable, - StyleSheet, - Text, - View, -} from 'react-native' +import { Pressable, StyleSheet, Text, View } from 'react-native' const INITIAL_MESSAGES = Array.from({ length: 8 }, (_, index) => ({ id: `message-${index + 1}`, diff --git a/evals/lists/17-rn-legendlist-chat-start-from-bottom/reference/App.tsx b/evals/lists/17-rn-legendlist-chat-start-from-bottom/reference/App.tsx index 832b2e71..cbf81d5c 100644 --- a/evals/lists/17-rn-legendlist-chat-start-from-bottom/reference/App.tsx +++ b/evals/lists/17-rn-legendlist-chat-start-from-bottom/reference/App.tsx @@ -1,10 +1,5 @@ import React, { useState } from 'react' -import { - Pressable, - StyleSheet, - Text, - View, -} from 'react-native' +import { Pressable, StyleSheet, Text, View } from 'react-native' import { LegendList } from '@legendapp/list/react-native' const INITIAL_MESSAGES = Array.from({ length: 8 }, (_, index) => ({ diff --git a/evals/lists/18-rn-legendlist-expandable-cards-recycling-state/reference/App.tsx b/evals/lists/18-rn-legendlist-expandable-cards-recycling-state/reference/App.tsx index 24917830..d23f4714 100644 --- a/evals/lists/18-rn-legendlist-expandable-cards-recycling-state/reference/App.tsx +++ b/evals/lists/18-rn-legendlist-expandable-cards-recycling-state/reference/App.tsx @@ -1,14 +1,6 @@ import React from 'react' -import { - Pressable, - StyleSheet, - Text, - View, -} from 'react-native' -import { - LegendList, - useRecyclingState, -} from '@legendapp/list/react-native' +import { Pressable, StyleSheet, Text, View } from 'react-native' +import { LegendList, useRecyclingState } from '@legendapp/list/react-native' const FAQS = [ { @@ -28,11 +20,7 @@ const FAQS = [ }, ] -function FaqCard({ - item, -}: { - item: (typeof FAQS)[number] -}) { +function FaqCard({ item }: { item: (typeof FAQS)[number] }) { const [isExpanded, setIsExpanded] = useRecyclingState(() => false) return ( diff --git a/evals/navigation/02-rn-nav-stack-filter-default/app/App.tsx b/evals/navigation/02-rn-nav-stack-filter-default/app/App.tsx index acac486b..0dab1adc 100644 --- a/evals/navigation/02-rn-nav-stack-filter-default/app/App.tsx +++ b/evals/navigation/02-rn-nav-stack-filter-default/app/App.tsx @@ -1,16 +1,24 @@ import React from 'react' import { createStaticNavigation } from '@react-navigation/native' -import type { - StaticParamList, -} from '@react-navigation/native' +import type { StaticParamList } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' import { Button, StyleSheet, View } from 'react-native' const NOTIFICATIONS = [ { id: 'n1', text: 'Welcome to the app', mentions: false, unread: false }, { id: 'n2', text: '@you commented on a post', mentions: true, unread: true }, - { id: 'n3', text: 'Build finished successfully', mentions: false, unread: true }, - { id: 'n4', text: '@you were assigned a task', mentions: true, unread: false }, + { + id: 'n3', + text: 'Build finished successfully', + mentions: false, + unread: true, + }, + { + id: 'n4', + text: '@you were assigned a task', + mentions: true, + unread: false, + }, ] as const function HomeScreen() { @@ -20,13 +28,13 @@ function HomeScreen() { return ( <View style={styles.container}> - <Button title='Open' onPress={openNotificationsDefault} /> + <Button title="Open" onPress={openNotificationsDefault} /> <Button - title='Open notifications (mentions)' + title="Open notifications (mentions)" onPress={openNotificationsMentions} /> <Button - title='Open notifications (unread)' + title="Open notifications (unread)" onPress={openNotificationsUnread} /> </View> diff --git a/evals/navigation/02-rn-nav-stack-filter-default/reference/App.tsx b/evals/navigation/02-rn-nav-stack-filter-default/reference/App.tsx index dc929154..18c2a6a7 100644 --- a/evals/navigation/02-rn-nav-stack-filter-default/reference/App.tsx +++ b/evals/navigation/02-rn-nav-stack-filter-default/reference/App.tsx @@ -10,8 +10,18 @@ import { Button, StyleSheet, Text, View } from 'react-native' const NOTIFICATIONS = [ { id: 'n1', text: 'Welcome to the app', mentions: false, unread: false }, { id: 'n2', text: '@you commented on a post', mentions: true, unread: true }, - { id: 'n3', text: 'Build finished successfully', mentions: false, unread: true }, - { id: 'n4', text: '@you were assigned a task', mentions: true, unread: false }, + { + id: 'n3', + text: 'Build finished successfully', + mentions: false, + unread: true, + }, + { + id: 'n4', + text: '@you were assigned a task', + mentions: true, + unread: false, + }, ] as const type Filter = 'all' | 'mentions' | 'unread' @@ -31,13 +41,13 @@ function HomeScreen() { return ( <View style={styles.container}> - <Button title='Open' onPress={openNotificationsDefault} /> + <Button title="Open" onPress={openNotificationsDefault} /> <Button - title='Open notifications (mentions)' + title="Open notifications (mentions)" onPress={openNotificationsMentions} /> <Button - title='Open notifications (unread)' + title="Open notifications (unread)" onPress={openNotificationsUnread} /> </View> diff --git a/evals/navigation/03-rn-nav-stack-header-from-param/app/App.tsx b/evals/navigation/03-rn-nav-stack-header-from-param/app/App.tsx index b923fdf6..f14aaf68 100644 --- a/evals/navigation/03-rn-nav-stack-header-from-param/app/App.tsx +++ b/evals/navigation/03-rn-nav-stack-header-from-param/app/App.tsx @@ -19,8 +19,8 @@ function HomeScreen() { <View style={styles.container}> <Text style={styles.title}>People</Text> <Text>{`Items: ${PEOPLE.map((person) => person.name).join(', ')}`}</Text> - <Button title='Open Alice' onPress={openAlice} /> - <Button title='Open Bob' onPress={openBob} /> + <Button title="Open Alice" onPress={openAlice} /> + <Button title="Open Bob" onPress={openBob} /> </View> ) } diff --git a/evals/navigation/03-rn-nav-stack-header-from-param/reference/App.tsx b/evals/navigation/03-rn-nav-stack-header-from-param/reference/App.tsx index e4d4cd9a..ec872d86 100644 --- a/evals/navigation/03-rn-nav-stack-header-from-param/reference/App.tsx +++ b/evals/navigation/03-rn-nav-stack-header-from-param/reference/App.tsx @@ -27,8 +27,8 @@ function HomeScreen() { <View style={styles.container}> <Text style={styles.title}>People</Text> <Text>{`Items: ${PEOPLE.map((person) => person.name).join(', ')}`}</Text> - <Button title='Open Alice' onPress={openAlice} /> - <Button title='Open Bob' onPress={openBob} /> + <Button title="Open Alice" onPress={openAlice} /> + <Button title="Open Bob" onPress={openBob} /> </View> ) } diff --git a/evals/navigation/04-rn-nav-modal-compose-note/app/App.tsx b/evals/navigation/04-rn-nav-modal-compose-note/app/App.tsx index 85bd4fda..0a037555 100644 --- a/evals/navigation/04-rn-nav-modal-compose-note/app/App.tsx +++ b/evals/navigation/04-rn-nav-modal-compose-note/app/App.tsx @@ -42,7 +42,7 @@ function NotesScreen() { return ( <View style={styles.container}> <Text style={styles.title}>Notes</Text> - <Button title='Open' onPress={handleAddNote} /> + <Button title="Open" onPress={handleAddNote} /> {notes.length === 0 ? ( <Text>No notes yet</Text> ) : ( diff --git a/evals/navigation/06-rn-nav-home-tab-nested-details/app/App.tsx b/evals/navigation/06-rn-nav-home-tab-nested-details/app/App.tsx index e18c29bd..d59db58d 100644 --- a/evals/navigation/06-rn-nav-home-tab-nested-details/app/App.tsx +++ b/evals/navigation/06-rn-nav-home-tab-nested-details/app/App.tsx @@ -1,5 +1,8 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' -import { createStaticNavigation, StaticScreenProps } from '@react-navigation/native' +import { + createStaticNavigation, + StaticScreenProps, +} from '@react-navigation/native' import { Button, StyleSheet, Text, View } from 'react-native' function HomeFeedScreen() { @@ -9,10 +12,7 @@ function HomeFeedScreen() { <View style={styles.screen}> <Text style={styles.title}>HomeFeed</Text> <Text style={styles.copy}>Latest stories</Text> - <Button - title="Open" - onPress={handleNavigateToArticleDetails} - /> + <Button title="Open" onPress={handleNavigateToArticleDetails} /> </View> ) } @@ -39,7 +39,7 @@ function SettingsScreen() { } const TabNavigator = createBottomTabNavigator({ - id: "bottom-tab", + id: 'bottom-tab', screens: { HomeTab: HomeFeedScreen, Settings: SettingsScreen, diff --git a/evals/navigation/06-rn-nav-home-tab-nested-details/reference/App.tsx b/evals/navigation/06-rn-nav-home-tab-nested-details/reference/App.tsx index 010d9d06..9caa5925 100644 --- a/evals/navigation/06-rn-nav-home-tab-nested-details/reference/App.tsx +++ b/evals/navigation/06-rn-nav-home-tab-nested-details/reference/App.tsx @@ -19,9 +19,9 @@ const HomeStack = createNativeStackNavigator({ const TabNavigator = createBottomTabNavigator({ id: 'bottom-tab', screens: { - HomeTab: { + HomeTab: { screen: HomeStack, - options: { headerShown: false } + options: { headerShown: false }, }, Settings: SettingsScreen, }, @@ -48,10 +48,7 @@ function HomeScreen() { return ( <View style={styles.container}> - <Button - title="Open" - onPress={handleNavigateToArticleDetails} - /> + <Button title="Open" onPress={handleNavigateToArticleDetails} /> </View> ) } diff --git a/evals/navigation/10-rn-nav-deeplink-profile-basic/app/App.tsx b/evals/navigation/10-rn-nav-deeplink-profile-basic/app/App.tsx index ce6c653e..ef9af421 100644 --- a/evals/navigation/10-rn-nav-deeplink-profile-basic/app/App.tsx +++ b/evals/navigation/10-rn-nav-deeplink-profile-basic/app/App.tsx @@ -9,7 +9,7 @@ import { StyleSheet, Text, View } from 'react-native' function HomeScreen() { return ( <View style={styles.container}> - <Text style={styles.title}>Home</Text> + <Text style={styles.title}>Home</Text> </View> ) } diff --git a/evals/navigation/10-rn-nav-deeplink-profile-basic/reference/App.tsx b/evals/navigation/10-rn-nav-deeplink-profile-basic/reference/App.tsx index 5c1b9605..05853b98 100644 --- a/evals/navigation/10-rn-nav-deeplink-profile-basic/reference/App.tsx +++ b/evals/navigation/10-rn-nav-deeplink-profile-basic/reference/App.tsx @@ -10,7 +10,7 @@ import { Button, StyleSheet, Text, View } from 'react-native' function HomeScreen() { return ( <View style={styles.container}> - <Text style={styles.title}>Home</Text> + <Text style={styles.title}>Home</Text> </View> ) } diff --git a/evals/navigation/12-rn-nav-unsaved-edit-confirm/app/App.tsx b/evals/navigation/12-rn-nav-unsaved-edit-confirm/app/App.tsx index 400ecd2f..804260e5 100644 --- a/evals/navigation/12-rn-nav-unsaved-edit-confirm/app/App.tsx +++ b/evals/navigation/12-rn-nav-unsaved-edit-confirm/app/App.tsx @@ -1,9 +1,6 @@ import React, { useState } from 'react' -import { - createStaticNavigation, - useNavigation, -} from '@react-navigation/native' +import { createStaticNavigation, useNavigation } from '@react-navigation/native' import { createNativeStackNavigator, NativeStackNavigationProp, @@ -27,7 +24,7 @@ function HomeScreen() { return ( <View style={styles.container}> - <Button title='Open' onPress={handleEditProfile} /> + <Button title="Open" onPress={handleEditProfile} /> </View> ) } @@ -47,9 +44,14 @@ function EditScreen() { return ( <View style={styles.container}> - <TextInput style={styles.input} value={name} onChangeText={setName} placeholder='Name' /> - <Button title='Save' onPress={handleSave} /> - <Button title='Back' onPress={handleBack} /> + <TextInput + style={styles.input} + value={name} + onChangeText={setName} + placeholder="Name" + /> + <Button title="Save" onPress={handleSave} /> + <Button title="Back" onPress={handleBack} /> </View> ) } diff --git a/evals/navigation/12-rn-nav-unsaved-edit-confirm/reference/App.tsx b/evals/navigation/12-rn-nav-unsaved-edit-confirm/reference/App.tsx index 6cff5141..04d247a5 100644 --- a/evals/navigation/12-rn-nav-unsaved-edit-confirm/reference/App.tsx +++ b/evals/navigation/12-rn-nav-unsaved-edit-confirm/reference/App.tsx @@ -28,7 +28,7 @@ function HomeScreen() { return ( <View style={styles.container}> - <Button title='Open' onPress={handleEditProfile} /> + <Button title="Open" onPress={handleEditProfile} /> </View> ) } @@ -61,9 +61,14 @@ function EditScreen() { return ( <View style={styles.container}> - <TextInput style={styles.input} value={name} onChangeText={setName} placeholder='Name' /> - <Button title='Save' onPress={handleSave} /> - <Button title='Back' onPress={handleBack} /> + <TextInput + style={styles.input} + value={name} + onChangeText={setName} + placeholder="Name" + /> + <Button title="Save" onPress={handleSave} /> + <Button title="Back" onPress={handleBack} /> </View> ) } diff --git a/evals/navigation/13-rn-nav-focus-refresh-inbox/app/App.tsx b/evals/navigation/13-rn-nav-focus-refresh-inbox/app/App.tsx index 038c3d40..f8957a33 100644 --- a/evals/navigation/13-rn-nav-focus-refresh-inbox/app/App.tsx +++ b/evals/navigation/13-rn-nav-focus-refresh-inbox/app/App.tsx @@ -4,9 +4,7 @@ import { createStaticNavigation, useFocusEffect, } from '@react-navigation/native' -import { - createNativeStackNavigator, -} from '@react-navigation/native-stack' +import { createNativeStackNavigator } from '@react-navigation/native-stack' import { StyleSheet, Text, View } from 'react-native' type RootStackParamList = { diff --git a/evals/navigation/13-rn-nav-focus-refresh-inbox/reference/App.tsx b/evals/navigation/13-rn-nav-focus-refresh-inbox/reference/App.tsx index 550bca2d..bb2d05f3 100644 --- a/evals/navigation/13-rn-nav-focus-refresh-inbox/reference/App.tsx +++ b/evals/navigation/13-rn-nav-focus-refresh-inbox/reference/App.tsx @@ -4,9 +4,7 @@ import { createStaticNavigation, useFocusEffect, } from '@react-navigation/native' -import { - createNativeStackNavigator, -} from '@react-navigation/native-stack' +import { createNativeStackNavigator } from '@react-navigation/native-stack' import { StyleSheet, Text, View } from 'react-native' type RootStackParamList = { diff --git a/evals/react-native-apis/04-rn-image-network-dimensions/app/App.tsx b/evals/react-native-apis/04-rn-image-network-dimensions/app/App.tsx index 4b20d400..aaa2681f 100644 --- a/evals/react-native-apis/04-rn-image-network-dimensions/app/App.tsx +++ b/evals/react-native-apis/04-rn-image-network-dimensions/app/App.tsx @@ -1,8 +1,5 @@ import React from 'react' -import { - Text, - View, -} from 'react-native' +import { Text, View } from 'react-native' export default function App() { return ( diff --git a/evals/react-native-apis/04-rn-image-network-dimensions/reference/App.tsx b/evals/react-native-apis/04-rn-image-network-dimensions/reference/App.tsx index beb7bd77..9ec0bd85 100644 --- a/evals/react-native-apis/04-rn-image-network-dimensions/reference/App.tsx +++ b/evals/react-native-apis/04-rn-image-network-dimensions/reference/App.tsx @@ -1,15 +1,14 @@ import React from 'react' -import { - Image, - Text, - View, -} from 'react-native' +import { Image, Text, View } from 'react-native' export default function App() { return ( <View> <Text>Story</Text> - <Image source={{ uri: "https://placehold.co/200x100.png" }} style={{ width: 200, height: 100 }} /> + <Image + source={{ uri: 'https://placehold.co/200x100.png' }} + style={{ width: 200, height: 100 }} + /> </View> ) } diff --git a/evals/react-native-apis/05-rn-imagebackground-resize-mode/app/App.tsx b/evals/react-native-apis/05-rn-imagebackground-resize-mode/app/App.tsx index 3a61ffbb..f0abbdc3 100644 --- a/evals/react-native-apis/05-rn-imagebackground-resize-mode/app/App.tsx +++ b/evals/react-native-apis/05-rn-imagebackground-resize-mode/app/App.tsx @@ -1,9 +1,5 @@ import React from 'react' -import { - StyleSheet, - Text, - View, -} from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function App() { return ( diff --git a/evals/react-native-apis/05-rn-imagebackground-resize-mode/reference/App.tsx b/evals/react-native-apis/05-rn-imagebackground-resize-mode/reference/App.tsx index 58072956..3c2439a0 100644 --- a/evals/react-native-apis/05-rn-imagebackground-resize-mode/reference/App.tsx +++ b/evals/react-native-apis/05-rn-imagebackground-resize-mode/reference/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - ImageBackground, - StyleSheet, - Text, - View, -} from 'react-native' +import { ImageBackground, StyleSheet, Text, View } from 'react-native' export default function App() { return ( @@ -14,7 +9,7 @@ export default function App() { source={require('./banner.jpg')} imageStyle={styles.headerImage} style={styles.header} - resizeMode='cover' + resizeMode="cover" > <View style={styles.headerContent}> <Text style={styles.headerTitle}>Dock overview</Text> diff --git a/evals/react-native-apis/06-rn-platform-select-small-style-delta/app/App.tsx b/evals/react-native-apis/06-rn-platform-select-small-style-delta/app/App.tsx index 5b3f8bd6..55fb968e 100644 --- a/evals/react-native-apis/06-rn-platform-select-small-style-delta/app/App.tsx +++ b/evals/react-native-apis/06-rn-platform-select-small-style-delta/app/App.tsx @@ -1,9 +1,5 @@ import React from 'react' -import { - StyleSheet, - Text, - View, -} from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function App() { return ( diff --git a/evals/react-native-apis/06-rn-platform-select-small-style-delta/reference/App.tsx b/evals/react-native-apis/06-rn-platform-select-small-style-delta/reference/App.tsx index 839ef131..86cbb9bb 100644 --- a/evals/react-native-apis/06-rn-platform-select-small-style-delta/reference/App.tsx +++ b/evals/react-native-apis/06-rn-platform-select-small-style-delta/reference/App.tsx @@ -1,10 +1,5 @@ import React from 'react' -import { - Platform, - StyleSheet, - Text, - View, -} from 'react-native' +import { Platform, StyleSheet, Text, View } from 'react-native' const cardChrome = Platform.select({ android: { diff --git a/evals/react-native-apis/07-rn-platform-os-conditional-cta/app/App.tsx b/evals/react-native-apis/07-rn-platform-os-conditional-cta/app/App.tsx index d4fe4a96..037e3651 100644 --- a/evals/react-native-apis/07-rn-platform-os-conditional-cta/app/App.tsx +++ b/evals/react-native-apis/07-rn-platform-os-conditional-cta/app/App.tsx @@ -2,7 +2,7 @@ import React from 'react' import { Text, View } from 'react-native' export default function App() { - const platform = "placeholder" + const platform = 'placeholder' return ( <View> <Text>Platform: {platform}</Text> diff --git a/evals/react-native-apis/08-rn-platform-file-extension-component-split/reference/App.tsx b/evals/react-native-apis/08-rn-platform-file-extension-component-split/reference/App.tsx index 0c8a61e2..30ea19cc 100644 --- a/evals/react-native-apis/08-rn-platform-file-extension-component-split/reference/App.tsx +++ b/evals/react-native-apis/08-rn-platform-file-extension-component-split/reference/App.tsx @@ -1,7 +1,7 @@ import React from 'react' import { StyleSheet, Text, View } from 'react-native' -// @ts-expect-error we have not configured platform extensions +// @ts-expect-error we have not configured platform extensions import PlatformMessage from './PlatformMessage' export default function App() { diff --git a/evals/react-native-apis/09-rn-keyboardavoidingview-login-form/app/App.tsx b/evals/react-native-apis/09-rn-keyboardavoidingview-login-form/app/App.tsx index 79cb44a3..f314c82a 100644 --- a/evals/react-native-apis/09-rn-keyboardavoidingview-login-form/app/App.tsx +++ b/evals/react-native-apis/09-rn-keyboardavoidingview-login-form/app/App.tsx @@ -1,10 +1,5 @@ import React, { useState } from 'react' -import { - StyleSheet, - Text, - TextInput, - View, -} from 'react-native' +import { StyleSheet, Text, TextInput, View } from 'react-native' export default function App() { const [email, setEmail] = useState('') diff --git a/evals/skia/01-rn-skia-canvas-fill-background/reference/App.tsx b/evals/skia/01-rn-skia-canvas-fill-background/reference/App.tsx index 3bd2bed0..77c16c5a 100644 --- a/evals/skia/01-rn-skia-canvas-fill-background/reference/App.tsx +++ b/evals/skia/01-rn-skia-canvas-fill-background/reference/App.tsx @@ -1,5 +1,11 @@ import { Platform } from 'react-native' -import { Canvas, Fill, Text, matchFont, useCanvasSize } from '@shopify/react-native-skia' +import { + Canvas, + Fill, + Text, + matchFont, + useCanvasSize, +} from '@shopify/react-native-skia' const FONT_SIZE = 18 @@ -20,8 +26,8 @@ function CanvasContent() { return ( <> - <Fill color='#1e293b' /> - <Text x={textX} y={textY} text={label} font={font} color='#f8fafc' /> + <Fill color="#1e293b" /> + <Text x={textX} y={textY} text={label} font={font} color="#f8fafc" /> </> ) } diff --git a/evals/skia/05-rn-skia-linear-gradient/reference/App.tsx b/evals/skia/05-rn-skia-linear-gradient/reference/App.tsx index 9c479475..62a9b1ad 100644 --- a/evals/skia/05-rn-skia-linear-gradient/reference/App.tsx +++ b/evals/skia/05-rn-skia-linear-gradient/reference/App.tsx @@ -1,7 +1,18 @@ import { useEffect } from 'react' import { useWindowDimensions } from 'react-native' -import { Canvas, Fill, LinearGradient, interpolateColors, vec } from '@shopify/react-native-skia' -import { useDerivedValue, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated' +import { + Canvas, + Fill, + LinearGradient, + interpolateColors, + vec, +} from '@shopify/react-native-skia' +import { + useDerivedValue, + useSharedValue, + withRepeat, + withTiming, +} from 'react-native-reanimated' const START_COLORS = ['#6366f1', '#3b82f6', '#06b6d4', '#10b981'] const END_COLORS = ['#f59e0b', '#ef4444', '#ec4899', '#8b5cf6'] diff --git a/evals/skia/07-rn-skia-image-display/reference/App.tsx b/evals/skia/07-rn-skia-image-display/reference/App.tsx index 28c471d9..97796e6e 100644 --- a/evals/skia/07-rn-skia-image-display/reference/App.tsx +++ b/evals/skia/07-rn-skia-image-display/reference/App.tsx @@ -17,7 +17,7 @@ export default function App() { y={0} width={CANVAS_SIZE} height={CANVAS_SIZE} - fit='cover' + fit="cover" /> ) : ( <Rect @@ -25,7 +25,7 @@ export default function App() { y={0} width={CANVAS_SIZE} height={CANVAS_SIZE} - color='#334155' + color="#334155" /> )} </Canvas> diff --git a/evals/skia/13-rn-skia-animated-color-interpolation/reference/App.tsx b/evals/skia/13-rn-skia-animated-color-interpolation/reference/App.tsx index f5c128e5..25492554 100644 --- a/evals/skia/13-rn-skia-animated-color-interpolation/reference/App.tsx +++ b/evals/skia/13-rn-skia-animated-color-interpolation/reference/App.tsx @@ -1,6 +1,11 @@ import { useEffect } from 'react' import { Canvas, Fill, interpolateColors } from '@shopify/react-native-skia' -import { useDerivedValue, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated' +import { + useDerivedValue, + useSharedValue, + withRepeat, + withTiming, +} from 'react-native-reanimated' const COLORS = ['#6366f1', '#ec4899', '#f59e0b', '#10b981', '#6366f1'] const INPUT_RANGE = COLORS.map((_, i) => i) diff --git a/evals/skia/14-rn-skia-gesture-pan/reference/App.tsx b/evals/skia/14-rn-skia-gesture-pan/reference/App.tsx index d3025a3b..5f3ac5c5 100644 --- a/evals/skia/14-rn-skia-gesture-pan/reference/App.tsx +++ b/evals/skia/14-rn-skia-gesture-pan/reference/App.tsx @@ -16,15 +16,21 @@ export default function App() { cy.value += e.changeY }) .onEnd((e) => { - cx.value = withDecay({ velocity: e.velocityX, clamp: [RADIUS, width - RADIUS] }) - cy.value = withDecay({ velocity: e.velocityY, clamp: [RADIUS, height - RADIUS] }) + cx.value = withDecay({ + velocity: e.velocityX, + clamp: [RADIUS, width - RADIUS], + }) + cy.value = withDecay({ + velocity: e.velocityY, + clamp: [RADIUS, height - RADIUS], + }) }) return ( <GestureDetector gesture={gesture}> <Canvas style={{ flex: 1 }}> - <Fill color='#0f172a' /> - <Circle cx={cx} cy={cy} r={RADIUS} color='#f472b6' /> + <Fill color="#0f172a" /> + <Circle cx={cx} cy={cy} r={RADIUS} color="#f472b6" /> </Canvas> </GestureDetector> ) diff --git a/evals/skia/15-rn-skia-transforms/reference/App.tsx b/evals/skia/15-rn-skia-transforms/reference/App.tsx index c4fcf6b0..7f17e1c7 100644 --- a/evals/skia/15-rn-skia-transforms/reference/App.tsx +++ b/evals/skia/15-rn-skia-transforms/reference/App.tsx @@ -1,7 +1,12 @@ import { useEffect } from 'react' import { useWindowDimensions } from 'react-native' import { Canvas, Circle, Fill, Group, Rect } from '@shopify/react-native-skia' -import { useDerivedValue, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated' +import { + useDerivedValue, + useSharedValue, + withRepeat, + withTiming, +} from 'react-native-reanimated' const DURATION_MS = 3000 @@ -13,7 +18,11 @@ export default function App() { const angle = useSharedValue(0) useEffect(() => { - angle.value = withRepeat(withTiming(Math.PI * 2, { duration: DURATION_MS }), -1, false) + angle.value = withRepeat( + withTiming(Math.PI * 2, { duration: DURATION_MS }), + -1, + false + ) }, [angle]) const outerTransform = useDerivedValue(() => [ @@ -34,13 +43,13 @@ export default function App() { return ( <Canvas style={{ flex: 1 }}> - <Fill color='#0f172a' /> + <Fill color="#0f172a" /> <Group transform={outerTransform}> - <Circle cx={cx} cy={cy - 80} r={30} color='#38bdf8' /> - <Circle cx={cx} cy={cy + 80} r={30} color='#f472b6' /> - <Circle cx={cx - 80} cy={cy} r={30} color='#4ade80' /> - <Circle cx={cx + 80} cy={cy} r={30} color='#fb923c' /> + <Circle cx={cx} cy={cy - 80} r={30} color="#38bdf8" /> + <Circle cx={cx} cy={cy + 80} r={30} color="#f472b6" /> + <Circle cx={cx - 80} cy={cy} r={30} color="#4ade80" /> + <Circle cx={cx + 80} cy={cy} r={30} color="#fb923c" /> <Group transform={innerTransform}> <Rect @@ -48,7 +57,7 @@ export default function App() { y={cy - 20} width={40} height={40} - color='#facc15' + color="#facc15" /> </Group> </Group> diff --git a/evals/skia/16-rn-skia-clip-rect-and-path/reference/App.tsx b/evals/skia/16-rn-skia-clip-rect-and-path/reference/App.tsx index 29b51c73..5e4d6999 100644 --- a/evals/skia/16-rn-skia-clip-rect-and-path/reference/App.tsx +++ b/evals/skia/16-rn-skia-clip-rect-and-path/reference/App.tsx @@ -1,17 +1,28 @@ -import { Canvas, ClipPath, ClipRect, Fill, Group, LinearGradient, Rect, Skia, vec } from '@shopify/react-native-skia' +import { + Canvas, + ClipPath, + ClipRect, + Fill, + Group, + LinearGradient, + Rect, + Skia, + vec, +} from '@shopify/react-native-skia' -const STAR_SVG = 'M 160 30 L 190 110 L 280 110 L 210 160 L 240 240 L 160 190 L 80 240 L 110 160 L 40 110 L 130 110 Z' +const STAR_SVG = + 'M 160 30 L 190 110 L 280 110 L 210 160 L 240 240 L 160 190 L 80 240 L 110 160 L 40 110 L 130 110 Z' const starPath = Skia.Path.MakeFromSVGString(STAR_SVG)! export default function App() { return ( <Canvas style={{ flex: 1 }}> - <Fill color='#0f172a' /> + <Fill color="#0f172a" /> {/* ClipRect: restrict a gradient to a rectangle */} <Group> <ClipRect rect={{ x: 20, y: 60, width: 200, height: 140 }} /> - <Rect x={0} y={0} width={320} height={320} color='transparent'> + <Rect x={0} y={0} width={320} height={320} color="transparent"> <LinearGradient start={vec(0, 60)} end={vec(320, 200)} @@ -23,7 +34,7 @@ export default function App() { {/* ClipPath: clip a solid block to a star shape */} <Group> <ClipPath path={starPath} /> - <Rect x={0} y={240} width={320} height={320} color='#38bdf8' /> + <Rect x={0} y={240} width={320} height={320} color="#38bdf8" /> </Group> </Canvas> ) diff --git a/evals/skia/17-rn-skia-blend-mode/reference/App.tsx b/evals/skia/17-rn-skia-blend-mode/reference/App.tsx index 8cbc93b0..60cb04ff 100644 --- a/evals/skia/17-rn-skia-blend-mode/reference/App.tsx +++ b/evals/skia/17-rn-skia-blend-mode/reference/App.tsx @@ -10,11 +10,11 @@ export default function App() { return ( <Canvas style={{ flex: 1 }}> - <Fill color='white' /> - <Group blendMode='multiply'> - <Circle cx={cx} cy={cy - offset} r={r} color='cyan' /> - <Circle cx={cx - offset} cy={cy + offset / 2} r={r} color='magenta' /> - <Circle cx={cx + offset} cy={cy + offset / 2} r={r} color='yellow' /> + <Fill color="white" /> + <Group blendMode="multiply"> + <Circle cx={cx} cy={cy - offset} r={r} color="cyan" /> + <Circle cx={cx - offset} cy={cy + offset / 2} r={r} color="magenta" /> + <Circle cx={cx + offset} cy={cy + offset / 2} r={r} color="yellow" /> </Group> </Canvas> ) diff --git a/evals/skia/18-rn-skia-svg-path-rendering/reference/App.tsx b/evals/skia/18-rn-skia-svg-path-rendering/reference/App.tsx index 80a3b640..0caaf84b 100644 --- a/evals/skia/18-rn-skia-svg-path-rendering/reference/App.tsx +++ b/evals/skia/18-rn-skia-svg-path-rendering/reference/App.tsx @@ -1,4 +1,11 @@ -import { Canvas, Fill, LinearGradient, Path, Skia, vec } from '@shopify/react-native-skia' +import { + Canvas, + Fill, + LinearGradient, + Path, + Skia, + vec, +} from '@shopify/react-native-skia' const HEART_SVG = 'M 128 96 C 128 96 80 40 32 72 C -8 96 16 160 64 192 L 128 240 L 192 192 C 240 160 264 96 224 72 C 176 40 128 96 128 96 Z' @@ -8,9 +15,9 @@ const heartPath = Skia.Path.MakeFromSVGString(HEART_SVG)! export default function App() { return ( <Canvas style={{ flex: 1 }}> - <Fill color='#0f172a' /> + <Fill color="#0f172a" /> - <Path path={heartPath} color='transparent'> + <Path path={heartPath} color="transparent"> <LinearGradient start={vec(32, 40)} end={vec(224, 240)} @@ -20,10 +27,10 @@ export default function App() { <Path path={heartPath} - color='#fda4af' - style='stroke' + color="#fda4af" + style="stroke" strokeWidth={3} - strokeJoin='round' + strokeJoin="round" /> </Canvas> ) diff --git a/evals/skia/19-rn-skia-runtime-effect-shader/reference/App.tsx b/evals/skia/19-rn-skia-runtime-effect-shader/reference/App.tsx index f1f9a38b..df027414 100644 --- a/evals/skia/19-rn-skia-runtime-effect-shader/reference/App.tsx +++ b/evals/skia/19-rn-skia-runtime-effect-shader/reference/App.tsx @@ -1,7 +1,12 @@ import { useEffect } from 'react' import { useWindowDimensions } from 'react-native' import { Canvas, Fill, Shader, Skia, vec } from '@shopify/react-native-skia' -import { useDerivedValue, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated' +import { + useDerivedValue, + useSharedValue, + withRepeat, + withTiming, +} from 'react-native-reanimated' const SKSL = ` uniform float2 resolution; @@ -23,7 +28,11 @@ export default function App() { const time = useSharedValue(0) useEffect(() => { - time.value = withRepeat(withTiming(Math.PI * 2, { duration: 3000 }), -1, false) + time.value = withRepeat( + withTiming(Math.PI * 2, { duration: 3000 }), + -1, + false + ) }, [time]) const uniforms = useDerivedValue(() => ({ diff --git a/evals/skia/20-rn-skia-canvas-snapshot/reference/App.tsx b/evals/skia/20-rn-skia-canvas-snapshot/reference/App.tsx index 856bb96d..4faaa88f 100644 --- a/evals/skia/20-rn-skia-canvas-snapshot/reference/App.tsx +++ b/evals/skia/20-rn-skia-canvas-snapshot/reference/App.tsx @@ -17,10 +17,10 @@ export default function App() { return ( <View style={styles.container}> <Canvas style={styles.canvas} ref={ref}> - <Fill color='#1e293b' /> - <Circle cx={160} cy={200} r={80} color='#38bdf8' /> - <Circle cx={100} cy={320} r={50} color='#f472b6' /> - <Circle cx={220} cy={320} r={50} color='#4ade80' /> + <Fill color="#1e293b" /> + <Circle cx={160} cy={200} r={80} color="#38bdf8" /> + <Circle cx={100} cy={320} r={50} color="#f472b6" /> + <Circle cx={220} cy={320} r={50} color="#4ade80" /> </Canvas> <TouchableOpacity style={styles.button} onPress={handleSave}> diff --git a/evals/skia/24-rn-skia-picture-save-restore/reference/App.tsx b/evals/skia/24-rn-skia-picture-save-restore/reference/App.tsx index a856677c..0b4930ec 100644 --- a/evals/skia/24-rn-skia-picture-save-restore/reference/App.tsx +++ b/evals/skia/24-rn-skia-picture-save-restore/reference/App.tsx @@ -25,7 +25,12 @@ export default function App() { canvas.translate(CX, 90) canvas.rotate(FIRST_RECT_ROTATION_DEG) canvas.drawRect( - { x: -RECT_WIDTH / 2, y: -RECT_HEIGHT / 2, width: RECT_WIDTH, height: RECT_HEIGHT }, + { + x: -RECT_WIDTH / 2, + y: -RECT_HEIGHT / 2, + width: RECT_WIDTH, + height: RECT_HEIGHT, + }, paint ) canvas.restore() @@ -38,7 +43,12 @@ export default function App() { canvas.translate(CX, 230) canvas.rotate(THIRD_RECT_ROTATION_DEG) canvas.drawRect( - { x: -RECT_WIDTH / 2, y: -RECT_HEIGHT / 2, width: RECT_WIDTH, height: RECT_HEIGHT }, + { + x: -RECT_WIDTH / 2, + y: -RECT_HEIGHT / 2, + width: RECT_WIDTH, + height: RECT_HEIGHT, + }, paint ) canvas.restore() diff --git a/evals/skia/README.md b/evals/skia/README.md index 3b18ea2d..6cefe82b 100644 --- a/evals/skia/README.md +++ b/evals/skia/README.md @@ -23,25 +23,25 @@ React Native Skia evals — testing how well LLMs implement high-performance 2D ## Best-practice inventory -| # | Rule | Source | -| --- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | -| 1 | Render all Skia drawing inside a `<Canvas>` root component | canvas/overview | -| 2 | Pass Reanimated `useSharedValue` / `useDerivedValue` directly as Skia props — no `createAnimatedComponent` or `useAnimatedProps` needed | animations/animations | -| 3 | Use `interpolateColors` from `@shopify/react-native-skia`, not `interpolateColor` from Reanimated, for color transitions | animations/animations | -| 4 | Wrap gesture handlers around the `<Canvas>` using `GestureDetector`; for per-element gesture tracking, overlay an `Animated.View` | animations/gestures | -| 5 | Use `useCanvasSize` (JS thread) or the `onSize` shared value prop (UI thread) to read canvas dimensions reactively | canvas/overview | -| 6 | Build paths imperatively with `Skia.Path.Make()` or parse SVG strings with `Skia.Path.MakeFromSVGString` | shapes/path | -| 7 | Use `Paint` children on drawing elements for multiple fills/strokes; inherit paint attributes via `Group` | paint/overview | -| 8 | Compose image filters by nesting `Blur`, `ColorMatrix`, etc. as children of the target drawing element or `Group` | image-filters/overview | -| 9 | Compile custom SKSL shaders with `Skia.RuntimeEffect.Make`; use the `Shader` component as a child of `Fill` | shaders/overview | -| 10 | Capture canvas output with `makeImageSnapshot()` via `useCanvasRef`; call `encodeToBytes()` for raw pixel data | canvas/overview | -| 11 | Use `matchFont` with a `fontStyle` object for system font resolution; the Text `y` origin is the text baseline, not the top | text/text | -| 12 | Apply blend modes at the `Group` level with the `blendMode` prop to composite child elements | paint/overview | -| 13 | Use `ClipRect` / `ClipPath` as children of a `Group` or drawing element to mask content | canvas/overview | -| 14 | Use `SweepGradient` / `TwoPointConicalGradient` for angular and conical fills beyond linear/radial | shaders/gradients | -| 15 | Apply effects to a group composite with the `layer` prop (`<Paint>` + image filters), not per-child filters alone | group | -| 16 | Use `Skia.ParagraphBuilder` + `<Paragraph>` for multi-style text layouts; call `layout(width)` before rendering | text/paragraph | -| 17 | Isolate imperative canvas transforms with `canvas.save()` / `canvas.restore()` inside a recorded `Picture` | shapes/pictures | +| # | Rule | Source | +| --- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | +| 1 | Render all Skia drawing inside a `<Canvas>` root component | canvas/overview | +| 2 | Pass Reanimated `useSharedValue` / `useDerivedValue` directly as Skia props — no `createAnimatedComponent` or `useAnimatedProps` needed | animations/animations | +| 3 | Use `interpolateColors` from `@shopify/react-native-skia`, not `interpolateColor` from Reanimated, for color transitions | animations/animations | +| 4 | Wrap gesture handlers around the `<Canvas>` using `GestureDetector`; for per-element gesture tracking, overlay an `Animated.View` | animations/gestures | +| 5 | Use `useCanvasSize` (JS thread) or the `onSize` shared value prop (UI thread) to read canvas dimensions reactively | canvas/overview | +| 6 | Build paths imperatively with `Skia.Path.Make()` or parse SVG strings with `Skia.Path.MakeFromSVGString` | shapes/path | +| 7 | Use `Paint` children on drawing elements for multiple fills/strokes; inherit paint attributes via `Group` | paint/overview | +| 8 | Compose image filters by nesting `Blur`, `ColorMatrix`, etc. as children of the target drawing element or `Group` | image-filters/overview | +| 9 | Compile custom SKSL shaders with `Skia.RuntimeEffect.Make`; use the `Shader` component as a child of `Fill` | shaders/overview | +| 10 | Capture canvas output with `makeImageSnapshot()` via `useCanvasRef`; call `encodeToBytes()` for raw pixel data | canvas/overview | +| 11 | Use `matchFont` with a `fontStyle` object for system font resolution; the Text `y` origin is the text baseline, not the top | text/text | +| 12 | Apply blend modes at the `Group` level with the `blendMode` prop to composite child elements | paint/overview | +| 13 | Use `ClipRect` / `ClipPath` as children of a `Group` or drawing element to mask content | canvas/overview | +| 14 | Use `SweepGradient` / `TwoPointConicalGradient` for angular and conical fills beyond linear/radial | shaders/gradients | +| 15 | Apply effects to a group composite with the `layer` prop (`<Paint>` + image filters), not per-child filters alone | group | +| 16 | Use `Skia.ParagraphBuilder` + `<Paragraph>` for multi-style text layouts; call `layout(width)` before rendering | text/paragraph | +| 17 | Isolate imperative canvas transforms with `canvas.save()` / `canvas.restore()` inside a recorded `Picture` | shapes/pictures | | 18 | Load Lottie JSON with `Skia.Skottie.Make(JSON.stringify(...))`; drive `<Skottie>` playback with `useClock` and a Reanimated derived frame | skottie | ## Eval traceability diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 00000000..89d10799 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,16 @@ +pre-commit: + jobs: + - name: format + run: bunx prettier --write {staged_files} + glob: '*.{js,ts,mjs,cjs,json,md,yml,yaml,tsx}' + stage_fixed: true + + - group: + parallel: true + jobs: + - name: lint + run: bunx eslint {staged_files} + glob: '*.{js,ts,mjs,tsx}' + + - name: typecheck + run: bun run typecheck diff --git a/package.json b/package.json index cf8c57b7..da60fe39 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,12 @@ "version": "0.3.0", "type": "module", "scripts": { + "prepare": "lefthook install", "lint": "eslint .", "format": "prettier --write .", "bench:run": "bun runner/run.ts", - "bench:judge": "bun runner/judge.ts" + "bench:judge": "bun runner/judge.ts", + "typecheck": "tsc --noEmit" }, "devDependencies": { "@types/node": "^25.2.2", @@ -19,6 +21,7 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "expo": "^54.0.33", "globals": "^15.14.0", + "lefthook": "^2.1.9", "prettier": "^3.8.1" }, "workspaces": [ diff --git a/runner/evaluators/llm/output.ts b/runner/evaluators/llm/output.ts index 182c7b9f..800b1167 100644 --- a/runner/evaluators/llm/output.ts +++ b/runner/evaluators/llm/output.ts @@ -6,9 +6,7 @@ import { sanitizeSegment } from 'runner/utils/fs' /* Creates run output directories and returns absolute paths used by writers. */ -export async function createRunOutputDirectories( - runDirectory: string -) { +export async function createRunOutputDirectories(runDirectory: string) { const resolvedRunDirectory = path.resolve(process.cwd(), runDirectory) await mkdir(resolvedRunDirectory, { recursive: true }) diff --git a/runner/evaluators/llm/tests/files.test.ts b/runner/evaluators/llm/tests/files.test.ts index e44c9816..f9d06d07 100644 --- a/runner/evaluators/llm/tests/files.test.ts +++ b/runner/evaluators/llm/tests/files.test.ts @@ -28,8 +28,12 @@ describe('files helpers', () => { const loaded = await loadFiles(rootDir) expect(loaded.length).toBe(2) - expect(loaded.some((file) => file.absolutePath.endsWith('root/README.md'))).toBe(true) - expect(loaded.some((file) => file.absolutePath.endsWith('root/nested/App.tsx'))).toBe(true) + expect( + loaded.some((file) => file.absolutePath.endsWith('root/README.md')) + ).toBe(true) + expect( + loaded.some((file) => file.absolutePath.endsWith('root/nested/App.tsx')) + ).toBe(true) }) test('returns empty array when directory does not exist', async () => { @@ -53,7 +57,9 @@ describe('files helpers', () => { await resetEvalOutputDirectory(outputDir) await writeFile(path.join(outputDir, 'App.tsx'), 'fresh') - await expect(access(path.join(outputDir, 'app', 'App.tsx'))).rejects.toThrow() + await expect( + access(path.join(outputDir, 'app', 'App.tsx')) + ).rejects.toThrow() const loaded = await loadFiles(outputDir) expect(loaded).toHaveLength(1) diff --git a/runner/solver/tests/concurrency.test.ts b/runner/solver/tests/concurrency.test.ts index 3705bd18..3d14849b 100644 --- a/runner/solver/tests/concurrency.test.ts +++ b/runner/solver/tests/concurrency.test.ts @@ -6,10 +6,14 @@ describe('runWithConcurrency', () => { test('preserves result ordering while using parallel workers', async () => { const values = [1, 2, 3, 4, 5] - const results = await runWithConcurrency(values, 2, async (value, _index, _workerIndex) => { - await new Promise((resolve) => setTimeout(resolve, 10 - value)) - return value * 10 - }) + const results = await runWithConcurrency( + values, + 2, + async (value, _index, _workerIndex) => { + await new Promise((resolve) => setTimeout(resolve, 10 - value)) + return value * 10 + } + ) expect(results).toEqual([10, 20, 30, 40, 50]) }) diff --git a/runner/utils/discovery.ts b/runner/utils/discovery.ts index 575049d8..c30b05f3 100644 --- a/runner/utils/discovery.ts +++ b/runner/utils/discovery.ts @@ -11,7 +11,9 @@ export type Eval = { /* Discovers eval directories by scanning for requirements.yaml files. */ -export async function discoverEvals(pattern = DISCOVERY_PATTERN): Promise<Eval[]> { +export async function discoverEvals( + pattern = DISCOVERY_PATTERN +): Promise<Eval[]> { const cwd = process.cwd() const glob = new Glob(path.join(pattern, 'requirements.yaml')) const matchingRequirements: string[] = [] diff --git a/runner/utils/generation-manifest.ts b/runner/utils/generation-manifest.ts index e7468e87..604bcf67 100644 --- a/runner/utils/generation-manifest.ts +++ b/runner/utils/generation-manifest.ts @@ -4,25 +4,29 @@ import { z } from 'zod' const GENERATION_MANIFEST_FILE_NAME = 'manifest.json' -const generationManifestEvalSchema = z.object({ - evalId: z.string().min(1), - evalPath: z.string().min(1), - outputFiles: z.array(z.string().min(1)), - generatedPath: z.string().min(1), - solverSessionArtifactPath: z.string().min(1), -}).strict() - -const generationManifestSchema = z.object({ - runId: z.string().min(1), - startedAt: z.string().datetime(), - finishedAt: z.string().datetime(), - solverModel: z.string().min(1), - pattern: z.string().min(1), - evalCount: z.number().int().nonnegative(), - evalsProcessed: z.number().int().nonnegative(), - evalsErrored: z.number().int().nonnegative(), - evals: z.array(generationManifestEvalSchema), -}).strict() +const generationManifestEvalSchema = z + .object({ + evalId: z.string().min(1), + evalPath: z.string().min(1), + outputFiles: z.array(z.string().min(1)), + generatedPath: z.string().min(1), + solverSessionArtifactPath: z.string().min(1), + }) + .strict() + +const generationManifestSchema = z + .object({ + runId: z.string().min(1), + startedAt: z.string().datetime(), + finishedAt: z.string().datetime(), + solverModel: z.string().min(1), + pattern: z.string().min(1), + evalCount: z.number().int().nonnegative(), + evalsProcessed: z.number().int().nonnegative(), + evalsErrored: z.number().int().nonnegative(), + evals: z.array(generationManifestEvalSchema), + }) + .strict() export type GenerationManifest = z.infer<typeof generationManifestSchema> diff --git a/runner/utils/opencode-agent-activity.ts b/runner/utils/opencode-agent-activity.ts index 1f1628a4..f9b735c9 100644 --- a/runner/utils/opencode-agent-activity.ts +++ b/runner/utils/opencode-agent-activity.ts @@ -1,4 +1,8 @@ -import { createOpencodeClient, type Event, type ToolPart } from '@opencode-ai/sdk' +import { + createOpencodeClient, + type Event, + type ToolPart, +} from '@opencode-ai/sdk' import { logOpencodeAgent, logOpencodeWarn } from './opencode' @@ -139,8 +143,8 @@ export function startOpencodeAgentActivityLogging(options: { `subscribing to agent events on port ${options.port}${options.directory ? ` directory=${options.directory}` : ''}` ) - void client - .event.subscribe({ + void client.event + .subscribe({ query: options.directory ? { directory: options.directory } : undefined, signal: abortController.signal, onSseEvent: (sseEvent) => { diff --git a/runner/utils/opencode-workspace.test.ts b/runner/utils/opencode-workspace.test.ts index 7289ef2c..303e3bad 100644 --- a/runner/utils/opencode-workspace.test.ts +++ b/runner/utils/opencode-workspace.test.ts @@ -13,21 +13,19 @@ describe('opencode workspace materialization', () => { const workspace = await createOpencodeTempDir() try { - await materializeSolverWorkspace( - workspace, - 'Implement the task.', - [ - { - path: 'App.tsx', - absolutePath: '/unused/App.tsx', - content: 'export default function App() {}', - }, - ] - ) + await materializeSolverWorkspace(workspace, 'Implement the task.', [ + { + path: 'App.tsx', + absolutePath: '/unused/App.tsx', + content: 'export default function App() {}', + }, + ]) await access(path.join(workspace, 'prompt.md')) await access(path.join(workspace, 'app', 'App.tsx')) - await expect(access(path.join(workspace, 'requirements.yaml'))).rejects.toThrow() + await expect( + access(path.join(workspace, 'requirements.yaml')) + ).rejects.toThrow() await expect(access(path.join(workspace, 'reference'))).rejects.toThrow() } finally { await cleanupOpencodeTempDir(workspace) diff --git a/runner/utils/opencode.test.ts b/runner/utils/opencode.test.ts index 74f7973b..5e789ddb 100644 --- a/runner/utils/opencode.test.ts +++ b/runner/utils/opencode.test.ts @@ -167,12 +167,12 @@ describe('opencode docker env passthrough', () => { expect(shouldPassthroughOpencodeDockerEnvKey('CLOUDFLARE_API_TOKEN')).toBe( true ) - expect( - shouldPassthroughOpencodeDockerEnvKey('CLOUDFLARE_ACCOUNT_ID') - ).toBe(true) - expect( - shouldPassthroughOpencodeDockerEnvKey('CLOUDFLARE_GATEWAY_ID') - ).toBe(true) + expect(shouldPassthroughOpencodeDockerEnvKey('CLOUDFLARE_ACCOUNT_ID')).toBe( + true + ) + expect(shouldPassthroughOpencodeDockerEnvKey('CLOUDFLARE_GATEWAY_ID')).toBe( + true + ) }) test('passes provider-prefixed env vars through to containers', () => { @@ -180,9 +180,9 @@ describe('opencode docker env passthrough', () => { expect(shouldPassthroughOpencodeDockerEnvKey('ANTHROPIC_API_KEY')).toBe( true ) - expect(shouldPassthroughOpencodeDockerEnvKey('OPENCODE_SERVER_LOG_LEVEL')).toBe( - true - ) + expect( + shouldPassthroughOpencodeDockerEnvKey('OPENCODE_SERVER_LOG_LEVEL') + ).toBe(true) }) test('does not pass unrelated env vars through to containers', () => {