Files
Emberfall/docs/CODING_STANDARDS.md

46 lines
2.3 KiB
Markdown

# CODING_STANDARDS.md
## Language & style
- Node 20+, CommonJS, `'use strict'` not needed in CJS modules but harmless.
- 2-space indent, semicolons, single quotes, trailing commas in multiline literals.
- `const` by default; `let` only if reassigned; never `var`.
- Names: `camelCase` functions/vars, `PascalCase` classes, `UPPER_SNAKE` constants, `snake_case` DB columns.
- Convert DB `snake_case` rows → `camelCase` objects at the service boundary (one small mapper per entity).
- Functions do one thing and fit on a screen (< 40 lines). Early returns over deep nesting.
- Comments explain *why*, not *what*. Add a one-line header comment to each file describing its purpose.
## Errors
Create `src/utils/errors.js`:
```js
class AppError extends Error {
constructor(code, message, status = 400) { super(message); this.code = code; this.status = status; }
}
```
- Services throw `AppError` for expected failures (`new AppError('INSUFFICIENT_ENERGY','Not enough energy.',422)`).
- Routes use an async wrapper so thrown errors reach `errorHandler`:
```js
const wrap = (fn) => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);
```
- `errorHandler` maps `AppError` → envelope; `ZodError` → 400 `VALIDATION_ERROR`; anything else → 500 generic message + server log.
## Pure game code
- `src/game/*` exports plain functions; no I/O; no `Date.now()`; no `Math.random()` — take `rng` / `nowMs` params.
- Return new objects instead of mutating inputs.
## Database access
- One prepared statement per query, created once at module load (or lazily cached), not inside loops.
- Wrap multi-write operations in `db.transaction`.
- Never `SELECT *` in services for public output; select what you return.
## Frontend JS
- `public/js/api.js` exports a small `api(method, path, body)` wrapper that handles JSON, error envelope, and 401 → redirect to login.
- DOM updates via `textContent` / `createElement`. No `innerHTML` with dynamic data.
- One JS file per page + shared `api.js` and `ui.js` (toasts, formatting).
- No global state beyond a single `state` object per page.
## Logging
`src/utils/logger.js`: tiny wrapper over `console` with levels; silent in tests unless `LOG=1`.
## Dependencies
Pinned in package.json via `npm install --save-exact`. No dependency without need (NOTES.md §2.3).