Add lint, typecheck, and html-validate guardrails

Tooling:
- ESLint 9 flat config (eslint.config.mjs) with three scopes:
  - browser vanilla JS for js/ (no modules, window globals)
  - Node ESM for scripts/
  - typescript-eslint for tests/ and *.ts
- Stylelint with a deliberately minimal "bug-only" ruleset
  (block-no-empty, color-no-invalid-hex, function-no-unknown,
  property-no-unknown, …) — no nags about compact handwritten CSS
- html-validate against index.html (DOCTYPE, accessible names,
  non-redundant ARIA roles, valid landmark usage)
- TypeScript --noEmit strict on playwright.config.ts + tests/*.ts

npm scripts:
- lint        — parallel run of lint:js, lint:css, lint:html (~3s)
- lint:js{,:fix}, lint:css{,:fix}, lint:html
- typecheck   — tsc --noEmit
- check       — lint + typecheck + test in parallel (CI entry point)

Fixes uncovered by the new checks:
- js/app.js: drop unused `activeTimers`, drop unused `t` lookup in
  refreshTreeRow, switch `activeTags` let→const, replace empty
  `catch(_)` blocks with parameter-less catch + intent comment
- js/data.js: drop unused index arg in renderExperience
- index.html: uppercase DOCTYPE, drop redundant role="banner" /
  role="contentinfo" on <header>/<footer>, add aria-labels on icon-only
  Stop / Reset buttons, add role="group" to the tag bar so its
  aria-label is valid, add explicit type="button" everywhere
- tests/portfolio.spec.ts: landmark test now uses getByRole() rather
  than the explicit [role="banner"] attribute selector

Housekeeping:
- .gitignore picks up .eslintcache / .stylelintcache / *.tsbuildinfo
- README documents the lint + check toolchain

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Builder
2026-05-11 23:06:42 -04:00
co-authored by Cursor
parent b596b2d608
commit 6f897fafb9
12 changed files with 3447 additions and 29 deletions
+24
View File
@@ -120,6 +120,30 @@ BASE_URL=https://iliadobkin.com npx playwright test
---
## Lint & quality checks
The site has no build step, but the dev toolchain runs a four-step quality pass on every commit-worthy change. All checks have an npm script and can be run individually.
```bash
npm run lint # eslint + stylelint + html-validate, in parallel
npm run lint:js # ESLint over js/, scripts/, tests/, *.ts (vanilla JS + TS)
npm run lint:css # Stylelint over css/*.css (bug-only ruleset, no style nags)
npm run lint:html # html-validate over index.html (a11y, roles, DOCTYPE)
npm run typecheck # tsc --noEmit on playwright.config.ts + tests/*.ts
npm run check # lint + typecheck + test (the full guardrail set)
```
Conventions worth knowing:
- **ESLint** uses a flat config (`eslint.config.mjs`) with three scopes — browser globals for `js/`, Node ESM for `scripts/`, and `typescript-eslint` for `tests/` + `*.ts`. `console.warn` / `console.error` are allowed; `console.log` is not.
- **Stylelint** runs a minimal "bug-only" ruleset (`.stylelintrc.json`) — block-no-empty, no-invalid-hex, function-no-unknown, property-no-unknown, etc. Compact handwritten CSS (single-line rules, `rgba()`, 6-char hex) is intentional and not flagged.
- **html-validate** (`.htmlvalidate.json`) enforces uppercase DOCTYPE, accessible button names, non-redundant ARIA roles, and valid landmark usage.
- **tsc** (`tsconfig.json`) runs in `--noEmit` strict mode against the test files — fails fast if a selector signature drifts.
`npm-run-all2` parallelizes the linters for speed (`npm run lint` finishes in ~3s); `npm run check` is the one to wire into a Gitea Actions runner.
---
## Editing content
**All content lives in [`js/data.js`](js/data.js)** under `window.PORTFOLIO`. Change a title, swap a job, retag a skill — the UI updates automatically because every section is rendered from this single object.