dex/CONTRIBUTING.md
chris 3a54cdcc53 Add a Vitest unit suite for the pure-logic modules
31 tests in test/, run in a plain Node env with a tiny localStorage shim
(no jsdom — its Node-22.4 transitive-dep breakage isn't worth working
around for logic tests):

- type-chart: modern effectiveness, dual-type stacking, and the era rules
  (no Fairy pre-6, Steel resists Ghost/Dark pre-6, the Gen 1 Ghost→Psychic
  and Bug↔Poison quirks).
- damage-calc: nature multipliers, the Gen 3+ stat formula (Garchomp
  reference values), STAB/effectiveness/immunity, pre/post-Gen-6 crit.
- savedex: a synthetic Gen 1 SRAM (bitfields + checksum) round-trips;
  checksum-mismatch and size guards.
- selection: normalizeSelection v2→v3 migration, per-game isolation,
  global favourite, stats vs statsNational.
- pokedex-resolver: prettify, dex resolution against a mini snapshot.

`npm test` wired into CI after format:check.

Also: docker-compose host port 8080 → 4753 (README updated).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-10 11:33:27 -04:00

137 lines
5.3 KiB
Markdown

# Contributing to Pocketdex
Thanks for taking the time. This is a small, framework-free codebase and
easy to get into.
## Ground rules
- **No copyrighted assets.** Don't commit Pokémon sprites, artwork, audio,
ROMs or save files. Everything visual is fetched at runtime from PokéAPI.
PRs that add such files will be asked to remove them.
- **Non-commercial.** No ads, analytics, telemetry, paid tiers, affiliate
links or "sign in" flows.
- **Stay framework-free.** No React/Vue/Svelte/etc., and no new runtime
dependencies without discussing it in an issue first. Build-time dev
dependencies are a lower bar but still worth raising.
- **Offline-first stays true.** The list, search, sort, filters and game
switching must keep working with no network. New always-needed data goes
in the snapshot, not a runtime fetch.
- **Be kind.** Assume good faith in issues and reviews.
## Getting set up
Requires **Node 20+**.
```bash
npm install
npm run snapshot # build src/data/snapshot.json from PokéAPI (git-ignored)
npm run dev # http://localhost:5173
```
To exercise the service worker, offline behaviour or the install prompt,
you need a real build:
```bash
npm run build && npm run preview
```
## Where things live
See the **Project layout** and **How it works** sections in
[README.md](README.md). In short:
- `src/views/<Name>.js` — one file per route, an `async` function returning
a DOM node. Register it in `src/router.js`.
- `src/components/` — reusable pieces (`Card`, `Sprite`, `TypeChip`, …).
- `src/store/``createStore()`-backed reactive state, persisted to
`localStorage` under `pdx.*`.
- `src/lib/` — framework-y helpers with no app knowledge (`dom`, `anim`,
`damage-calc`, `savedex`, …).
- `src/data/` — the snapshot loader, the Pokédex resolver, the lazy PokéAPI
client, the type chart, natures.
- `scripts/build-snapshot.mjs` — the only thing that talks to PokéAPI at
build time.
## Code style
Formatting is **Prettier** (`.prettierrc.json`). Run `npm run format`
before committing; CI runs `npm run format:check` and will fail on
unformatted code. There's no ESLint — for everything Prettier doesn't
decide, **match the surrounding code**:
- 2-space indent, semicolons, single quotes, 100-col width, trailing
commas (all handled by Prettier).
- Build DOM with the `el()` helper from `src/lib/dom.js`, not template
strings or `innerHTML` (except the deliberate `html:` prop for trusted
inline SVG).
- Stores: `set(fn)` **replaces** state — spread `...s` yourself. Read with
`get()`, react with `subscribe()`, and unsubscribe in the view's
teardown (`onTeardown(view, off)`).
- Keep comments about _why_, not _what_. Match the existing density.
- Respect `prefersReducedMotion()` for any new animation.
- Keep everything game-aware: if you touch typings, type effectiveness,
learnsets or evolution, honour the selected game's generation
(`typesForGen`, `multiplier(atk, def, gen)`, `past_values`, …).
## Common tasks
**Add a setting** — add the key + default to `src/store/settings.js`
(and `applyTheme()` if it affects the document), then a field in
`src/views/SettingsView.js`. Add it to the export payload if it should
survive a backup.
**Add a snapshot field** — add it in `scripts/build-snapshot.mjs`, run
`npm run snapshot -- --force`, and consume it via `loadSnapshot()`. Keep
the snapshot small; it's precached on every install.
**Add a route** — new file in `src/views/`, one entry in the `routes`
array in `src/router.js`. Add a skeleton if the view does async work
before it can render.
## Testing your change
There's a small [Vitest](https://vitest.dev/) suite in `test/` covering
pure logic — the type chart, damage formula, the save-file parser, and the
per-game selection store. Run it with `npm test` (watch mode:
`npm run test:watch`). If you change any of those modules, update or add a
test. There are no UI/integration tests.
CI runs `npm run format:check`, `npm test`, and `npm run build`. Before
opening a PR also check by hand:
- The **dex grid** — filters, sort, the progress ring, catching from a
card.
- **Switching games** (the Games sheet) — regional numbers, era typings,
and per-game seen/caught all update.
- A **detail page** — every tab, form switching, the track buttons.
- `npm run preview` still works offline (DevTools → Network → Offline,
then reload).
- Light **and** dark theme, and a narrow (mobile) viewport.
Describe what you tested in the PR.
## Commits & pull requests
- Branch off `main`. One focused change per PR.
- Imperative commit subjects ("Add …", "Fix …"), with a body explaining
the _why_ when it isn't obvious.
- Don't commit `dist/` or `src/data/snapshot.json` (both git-ignored).
- Fill in the PR template. Screenshots or a short clip for anything
visual.
- It's fine to open a draft PR early to discuss direction.
- AI-assisted contributions are welcome — say so in the PR description if a
tool wrote a meaningful part of it, and review it yourself first. The
same bar applies either way. This project is itself built this way (see
the README).
## Reporting bugs
Open an issue with: what you did, what you expected, what happened, the
browser/OS, and the selected game if it's relevant. A screenshot or the
console output helps a lot.
## License
By contributing you agree that your contributions are licensed under the
[MIT License](LICENSE).