Skip to content

BBC2-34 adopt Biome + scoped ESLint for formatting and architecture rules#12

Merged
b2l merged 3 commits into
mainfrom
b2lpowa/bbc2-34-enforce-commands-backend-shared-import-rule-with-a-linter
Apr 15, 2026
Merged

BBC2-34 adopt Biome + scoped ESLint for formatting and architecture rules#12
b2l merged 3 commits into
mainfrom
b2lpowa/bbc2-34-enforce-commands-backend-shared-import-rule-with-a-linter

Conversation

@b2l
Copy link
Copy Markdown
Owner

@b2l b2l commented Apr 14, 2026

Summary

Two problems, one tooling decision:

  1. Consistent formatting — stop relying on whoever happens to type next.
  2. Architectural rule enforcement — prevent accidental violations of the commands → backend → shared dependency rule.

Replaces the earlier custom bun test walker with:

  • Biome for formatting + general lint. Zero-config defaults (tab indent, double quotes, trailing commas).
  • ESLint, scoped narrowly, for the boundaries/dependencies rule only. No formatting, no general lint.
  • No Prettier — Biome covers formatting; adding Prettier means two tools arguing about the same line.

What changed

  • biome.json — formatter + linter config, three rules disabled globally for legitimate patterns (see commit for rationale).
  • eslint.config.js — flat config, only boundaries/dependencies rule enabled.
  • package.json — new dev deps (@biomejs/biome, eslint, eslint-plugin-boundaries, @typescript-eslint/parser), new scripts (format, lint).
  • One-time format sweep across the codebase (tabs now, previously spaces).
  • Two manual reverts of Biome unsafe-fix ?. rewrites that changed semantics in repository/{parse-url,resolve}.ts.
  • src/shared/config/index.ts — typed proc explicitly with Bun.Subprocess<"ignore","pipe","pipe"> to satisfy noImplicitAnyLet.

Why not stay on the custom walker

The bun test walker worked, but:

  • No editor feedback — violations surfaced only on test runs.
  • We wanted formatting anyway; Biome gets pulled in for that.
  • Declarative ESLint rule is ~15 lines vs ~100 LOC of custom code.

Verified

  • bun test — 128 pass.
  • bunx tsc --noEmit — clean.
  • bun run lint — clean (one harmless deprecation warning from eslint-plugin-boundaries v6 about legacy selector syntax in our config; the rule itself works).
  • Sanity: temporarily added a bad shared → backend import; ESLint correctly reported There is no rule allowing dependencies from elements of type "shared" to elements of type "backend".

CI wiring

BBC2-41 (not yet merged) adds bun test to CI. Once that lands, a trivial follow-up will add bun run lint to the CI workflow. Landing either first is fine — the workflow file change is a one-liner.

Editor integration

  • VS Code: install the Biome extension; set as default formatter. ESLint's default extension picks up the boundaries rule automatically.
  • Neovim: biome has an LSP; attach via nvim-lspconfig. ESLint likewise via eslint-lsp / none-ls.

Honest caveats

  • eslint-plugin-boundaries v6 deprecation warning at lint time. Migrating to v6's object-based selector syntax is a follow-up — my attempts hit schema validation errors I didn't fully untangle tonight. Functionally equivalent; just a warning.
  • The biome.json files.includes uses a whitelist shape because useIgnoreFile: true didn't cleanly exclude .direnv (nix-store symlinks) and .claude/worktrees/. Whitelist is less error-prone than chasing exclusions.

@b2l b2l force-pushed the b2lpowa/bbc2-34-enforce-commands-backend-shared-import-rule-with-a-linter branch from 70978e2 to 7aec1b0 Compare April 15, 2026 00:20
@b2l b2l changed the title BBC2-34 enforce layered import rule via bun test BBC2-34 adopt Biome + scoped ESLint for formatting and architecture rules Apr 15, 2026
@b2l b2l force-pushed the b2lpowa/bbc2-34-enforce-commands-backend-shared-import-rule-with-a-linter branch from 7aec1b0 to 22f320b Compare April 15, 2026 00:25
b2l added 2 commits April 15, 2026 00:32
…ules

Replaces the custom bun-test import walker with two opinionated tools:

  * Biome — formatting and general lint. Defaults apply (tab indent,
    double quotes, trailing commas), with three rules disabled because
    they conflict with legitimate patterns we use:
      - `style/noNonNullAssertion` — tests narrow `string | null` after
        msw handler mutation; the `!` assertion is correct.
      - `suspicious/noExplicitAny` — the Bitbucket response mapping uses
        `Record<string, any>` to cross the typed/untyped boundary.
      - `suspicious/noControlCharactersInRegex` — the renderer strips
        ANSI escapes via `\x1b[...]`, which is the control-char regex
        the rule flags.

  * ESLint, scoped to `boundaries/dependencies` only. No formatting, no
    general lint — Biome covers that. The rule encodes the layering:
      - commands may import backend + shared
      - backend/<slice> may import shared + same-slice backend
      - shared may import shared only

Biome's `files.includes` is whitelist-shaped (src, scripts, root configs)
because `useIgnoreFile: true` didn't reliably exclude .direnv symlinks
into /nix/store or .claude worktrees — an includes list is less
error-prone than chasing exclusions.

One-time format sweep: `biome check --write --unsafe` applied across the
repo. Most auto-fixes were safe (import sorting, template literals,
literal keys). One unsafe rewrite converted `match[1]!.toLowerCase()`
to `match[1]?.toLowerCase()` in repository/{parse-url,resolve}.ts — a
semantic change (non-null assertion → optional chain) — manually
reverted since the `!` was correct given a prior guard.

New scripts: `bun run format` (biome format --write .) and
`bun run lint` (biome check . && eslint src).

Sanity-verified: temporarily added `import type { CurrentUser } from
"../../backend/user/index.ts"` to src/shared/time/index.ts and
confirmed ESLint reports "There is no rule allowing dependencies from
elements of type 'shared' to elements of type 'backend'." Reverted
before commit.
Runs Checked 59 files in 595ms. No fixes applied. (biome check + eslint) before tsc/tests so
formatting and architecture violations fail before the more
expensive steps.
@b2l b2l force-pushed the b2lpowa/bbc2-34-enforce-commands-backend-shared-import-rule-with-a-linter branch from 22f320b to b4f72b1 Compare April 15, 2026 00:32
@b2l b2l closed this Apr 15, 2026
@b2l b2l reopened this Apr 15, 2026
@b2l b2l merged commit afdfec2 into main Apr 15, 2026
1 check passed
@b2l b2l deleted the b2lpowa/bbc2-34-enforce-commands-backend-shared-import-rule-with-a-linter branch April 15, 2026 00:38
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.

1 participant