Skip to content

feat: code quality enforcement (hooks, ESLint rules, style guide)#336

Open
Just-Insane wants to merge 11 commits intodevfrom
feat/code-quality
Open

feat: code quality enforcement (hooks, ESLint rules, style guide)#336
Just-Insane wants to merge 11 commits intodevfrom
feat/code-quality

Conversation

@Just-Insane
Copy link
Contributor

@Just-Insane Just-Insane commented Mar 17, 2026

Summary

Adds four layers of code quality enforcement to keep the codebase consistent.

Pre-commit hooks

  • Install husky + lint-staged — staged TS/JS files are auto-fixed with ESLint and formatted with Prettier on every commit

ESLint rules

  • @typescript-eslint/consistent-type-definitions — enforces type aliases over interface declarations
  • @typescript-eslint/consistent-type-imports — enforces import type / inline type modifier on type-only imports
  • no-restricted-properties — bans direct localStorage access inside src/app/components/** and src/app/features/**; use atoms or state utilities from src/app/state/ instead

Note: declare module augmentation files (slate.d.ts, matrix-sdk-events.d.ts) are exempt via targeted eslint-disable-next-line comments — both rules break module augmentation patterns that require real (non-type) imports and interface for declaration merging.

Codebase-wide lint fix

  • Applied pnpm lint:fix to enforce the two new type-import rules across ~500 existing files (0 new errors, 38 pre-existing no-console warnings remain)

State utilities

  • src/app/state/sentryStorage.ts — centralises Sentry opt-in preference reads/writes (plain functions, not atoms, so instrument.ts can call them synchronously before React mounts)
  • src/app/state/mediaVolume.ts — centralises media volume persistence

Test coverage enforcement

  • Coverage thresholds locked in vitest.config.ts and enforced by CI (pnpm test:coverage). Current baseline: ≥ 1.5% statements/functions/lines, ≥ 1% branches. These numbers are a floor — they should only ever be raised, never lowered.
  • Missing-tests advisory: On every PR, CI diffs changed logic files and posts a comment listing any without a .test.* counterpart. Advisory only — does not block merging. If tests aren't warranted (config tweaks, pure UI restyling), note it in the PR description.

Docs

  • docs/CODE_QUALITY.md — canonical reference covering TypeScript conventions, import ordering, naming, React patterns, Jotai/localStorage state patterns, vanilla-extract styling, testing policy (coverage thresholds + missing-tests advisory), and a full enforcement-layer table
  • Linked from CONTRIBUTING.md
  • Fixed stale upstream link in the PR template

Checklist

  • pnpm lint passes (0 errors)
  • All direct localStorage calls in components/features removed
  • Pre-commit hook verified working
  • Module augmentation .d.ts files exempted with targeted comments (no TS errors)
  • Coverage thresholds locked in vitest.config.ts
  • Coverage CI job added to quality-checks.yml
  • Missing-tests advisory CI job added to quality-checks.yml

… guards)

- Add husky + lint-staged pre-commit hooks (eslint --fix, prettier --write)
- Enable @typescript-eslint/consistent-type-definitions (type over interface)
- Enable @typescript-eslint/consistent-type-imports (inline type imports)
- Add ESLint rule banning direct localStorage in components/features
- Apply type-imports codebase-wide lint fix (~500 files)
- Add sentryStorage and mediaVolume utilities in src/app/state/
- Fix all direct localStorage violations in components/features
The consistent-type-definitions and consistent-type-imports rules
converted two module augmentation patterns in ways TypeScript doesn't
support:

- slate.d.ts: import { type X } from augmented module breaks the
  declare module augmentation; must use regular imports. Also reverts
  interface CustomTypes to interface (type aliases don't support
  declaration merging that Slate relies on).
- matrix-sdk-events.d.ts: type alias cannot merge with existing
  interface declarations in matrix-js-sdk; must use interface.

Add eslint-disable-next-line comments to suppress the rules at these
specific locations where they must be violated.
- Add vitest coverage thresholds (statements/functions/lines: 1.5%,
  branches: 1%) — locked at current baseline, never to be lowered
- Add 'coverage' CI job that runs pnpm test:coverage on every PR/push
- Add 'missing-tests' CI job that comments on PRs listing any changed
  logic files that have no corresponding .test. file (advisory, not
  blocking, to allow deliberate exceptions)
@Worldwave
Copy link

worried bot sounds

@Just-Insane Just-Insane marked this pull request as ready for review March 17, 2026 17:20
@Just-Insane Just-Insane requested review from 7w1 and hazre as code owners March 17, 2026 17:20
Copy link
Member

@hazre hazre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh github comments seem to be very spammy, I would maybe add a deduplication thing. I've done it for knope and cf previews. Also maybe it should only mention files touched by the PR.

@Just-Insane
Copy link
Contributor Author

Uh github comments seem to be very spammy, I would maybe add a deduplication thing. I've done it for knope and cf previews. Also maybe it should only mention files touched by the PR.

Will do - and those files are all touched by the PR, needed to be updated to pass the new lint rules

@github-actions

This comment was marked as spam.

@SableClient SableClient deleted a comment from github-actions bot Mar 17, 2026
@SableClient SableClient deleted a comment from github-actions bot Mar 17, 2026
@SableClient SableClient deleted a comment from github-actions bot Mar 17, 2026
@Just-Insane Just-Insane requested a review from hazre March 17, 2026 18:03
@Just-Insane
Copy link
Contributor Author

@hazre should update a single comment now. Also, as mentioned, all of those files were touched (they needed to be updated to match the new quality rules).

@Just-Insane Just-Insane enabled auto-merge March 17, 2026 18:51
auto-merge was automatically disabled March 17, 2026 23:35

Pull request was closed

@Just-Insane Just-Insane reopened this Mar 18, 2026
@Just-Insane Just-Insane marked this pull request as draft March 18, 2026 13:44
@Just-Insane Just-Insane marked this pull request as ready for review March 18, 2026 13:45
@github-actions
Copy link
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

Status Preview URL Commit Alias Updated (UTC)
✅ Deployment successful! https://pr-336-sable.raspy-dream-bb1d.workers.dev 494f38b pr-336 Thu, 19 Mar 2026 05:20:31 GMT

@SableClient SableClient deleted a comment from Just-Insane Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants