# 07 — Tooling & build
## Scripts
| `npm run …` | Does |
| --------------------- | -------------------------------------------------------- |
| `build` | `rm -rf dist && tsc --outDir dist` |
| `typecheck` | `tsc --noEmit`, then `tsc -p tsconfig.test.json` |
| `lint` | `oxlint src test` |
| `format` | `oxfmt '*.md' 'src/**/*.{ts,js,json,md}' 'test/**/*.ts'` |
| `test` / `test:watch` | `vitest run` / `vitest` |
## TypeScript 7
`package.json` pins `typescript@^7.0.2`. This choice constrains the lint
setup below. `tsconfig.json` highlights:
- `module: ESNext`, `moduleResolution: bundler`, `target: ESNext`
- `allowImportingTsExtensions` + `rewriteRelativeImportExtensions` — source
imports each other with explicit `.ts` extensions, and `tsc` rewrites them
to `.js` in the emitted output
- `declaration` + `declarationMap` — every module ships `.d.ts` + `.d.ts.map`
- `strict`, `isolatedModules`, `skipLibCheck`
- `include: ["src/**/*"]` only — `test/**` never reaches `dist/`. The
root-level `oxfmt.config.ts` is outside this glob too, so it's never
compiled.
## Linting: oxlint (not ESLint)
`oxlint.config.ts` — `oxlint@^1`, configured with `defineConfig`:
`plugins: ['typescript', 'unicorn', 'oxc']`, `categories` correctness→error /
suspicious+pedantic→warn, `max-lines*` and (in `test/`)
`max-classes-per-file` turned off.
**Why not `@typescript-eslint`:** it has no released version supporting
TypeScript 7 — its peer range caps at `<6.1.0`, and even loading
`@typescript-eslint/parser` crashes against TS 7's package shape. `oxlint`
has its own parser and never touches the `typescript` package, so it works
regardless of TS version.
**The tradeoff:** no type-aware rules — no `no-floating-promises`, no
`no-unnecessary-condition`, etc. Worth revisiting once `@typescript-eslint`
supports TS 7.
## Formatting: oxfmt
`oxfmt.config.ts` — `oxfmt` (the oxc project's formatter), configured with its
`defineConfig` default export:
```ts
export default defineConfig({
semi: true,
singleQuote: true,
trailingComma: 'all',
printWidth: 100,
tabWidth: 2,
});
```
- Same toolchain family as `oxlint`; single native binary, no plugin
ecosystem to pin against TS 7.
- Prettier-compatible options; the values above are Prettier's popular
defaults, so running `oxfmt` over the existing tree is a near no-op.
- oxfmt auto-discovers `oxfmt.config.ts` (search order: `.oxfmtrc.json` →
`.oxfmtrc.jsonc` → `oxfmt.config.ts` → `oxfmt.config.mts`); no `--config`
flag needed. It reads `.gitignore` automatically.
- One behavioural difference from Prettier: oxfmt formats fenced code blocks
_inside_ Markdown.
- Pre-1.0 — expect its output to shift between releases.
## Testing: Vitest + jsdom
`vitest.config.ts` — `environment: 'jsdom'`, `include: test/**/*.test.ts`,
`setupFiles: ['./test/setup.ts']`.
- **`test/setup.ts`** stubs `ResizeObserver` — jsdom doesn't implement it and
`leaflet-map.ts` constructs one unconditionally, so without the stub even
_importing_ the component throws. Nothing here depends on it firing.
- **Real Leaflet objects work under jsdom** for everything this library
verifies: option/attribute wiring, event forwarding, child binding. No
browser needed.
- **`onAdd()`-only state:** the `
`/`