Skip to content

feat: add Biome companion config package - #5

Merged
shaunburdick merged 12 commits into
mainfrom
001-biome-config
Aug 23, 2026
Merged

feat: add Biome companion config package#5
shaunburdick merged 12 commits into
mainfrom
001-biome-config

Conversation

@shaunburdick

Copy link
Copy Markdown
Owner

Summary

Adds biome/ — a shareable Biome 2.5 configuration (biome-config-shaunburdick) that ports the compatible subset of eslint-config-shaunburdick v9 rules to Biome's Rust-based linter/formatter.

  • ~91 rules ported across three layers in one commented biome.jsonc:
    • Base JS (~41): core style/correctness (eqeqeq, no-var, prefer-const, ...), complexity budgets (max 5 params, cognitive complexity 15), magic numbers, import-cycle detection
    • TypeScript **/*.{ts,tsx} (~31): typescript-eslint strict ports incl. native type-aware checks (noFloatingPromises, noMisusedPromises, noUnnecessaryConditions) — no tsc required
    • React (~19 + globals): full a11y suite, hooks deps, plus the 15 service-worker globals Biome lacks natively
  • Formatter owns style: 4-space indent, 120-char lines, single quotes; organizeImports assist replaces import-x/order
  • Full mapping analysis in specs/001-biome-config/research.md: every rule category machine-verified against Biome 2.5.10 via the official migrator + biome explain

Key decisions

  • Single-file config by design: empirically verified that Biome 2.5.10 silently drops linter sections from transitive extends inside published packages and does not resolve bare package subpaths in extends. Findings documented in the research addendum.
  • Globals audit: probed all 142 browser/serviceworker globals from the ESLint config — Biome natively knows 127; only 15 service-worker/new-platform handlers are declared.
  • Consumers opt in alongside ESLint, not instead of it (see gaps below).

Known gaps (ESLint-side only)

JSDoc linting, security plugin rules, promise discipline (always-return, catch-or-return), llm-core guardrails, naming denylist/length, and the custom shaunburdick/max-inline-disables rule have no Biome equivalent (GritQL plugins cannot match comments).

Test plan

  • npm test in biome/: validates biome.jsonc parses/checks clean + smoke fixtures prove enabled rules fire (4/4 passing)
  • Consumer-path simulation: package symlinked into a scratch node_modules, extended by bare name — all three layers confirmed firing on .js/.tsx probes
  • npm run lint in eslint/ still passes (ESLint package untouched)
  • CI wiring for biome/ (follow-up PR)

- biome/: shareable Biome 2.5 config porting ~91 compatible ESLint rules
  (base JS + TypeScript strict ports incl. native type-aware promise
  checks + React/a11y suite), formatter at 4-space/120-char/single-quote
  house style, organizeImports assist replaces import-x/order
- specs/001-biome-config/research.md: full rule-by-rule ESLint-to-Biome
  mapping analysis with verified rule categories and documented gaps
- Smoke test suite proves enabled rules fire on violation fixtures while
  the compliant fixture stays clean
- Sync AGENTS.md and root README with the new package
Biome 2.5.10 silently drops linter sections from transitive extends
inside published packages and does not resolve bare package subpaths
in extends, so the layer-split experiment is reverted in favor of a
single config file. Section banner comments (JSONC) restore navigability
across the base JS, TypeScript, and React layers.

Findings documented in specs/001-biome-config/research.md.
Probed all 142 browser+serviceworker globals bare against a minimal
Biome 2.5.10 config: 127 are built in, so carrying them was dead
weight. Kept only the service-worker/new-platform handlers that
actually need declaring. Smoke tests and consumer-path simulation
both verified.
npm audit began flagging brace-expansion (GHSA-3jxr-9vmj-r5cp et al,
high) and @babel/core (GHSA-4x5r-pxfx-6jf8, low) against versions
pinned since June. Lockfile-only refresh via npm audit fix; no
semver range changes, lint and rule tests pass.
- test-biome job mirrors test-eslint (Node 22/24/26 matrix, SHA-pinned
  actions, npm cache keyed on biome/package-lock.json)
- dependency-check now installs and audits both packages
eslint.yml returns to ESLint-only concerns; biome.yml owns Biome
testing (Node 22/24/26) and its dependency audit. Audit job named
distinctly (Biome Dependency Audit) to avoid required-check name
collisions across workflows.
- rename generic 'Dependency Vulnerability Check' to 'ES Lint
  Dependency Audit' so every package-scoped job is labeled by package
  (mirrors Biome Dependency Audit)
- add publish-biome: OIDC provenance publish + GitHub release on main,
  gated by test/audit like publish-eslint; release tags namespaced as
  biome-v* so the two packages can never collide on a tag
Repo-wide scanner no longer lives inside the ES Lint package workflow.
- New security.yml: Security Scan job, unfiltered push-to-main trigger
  keeps code-scanning alert state current; pull_request skips docs-only
  changes via paths-ignore
- eslint.yml: security-scan job removed, publish-eslint needs list
  trimmed (cross-workflow needs: is not possible)
- Check name 'Security Scan' unchanged so existing references keep working
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Top-level permissions: contents: read in every workflow so test and
audit jobs never inherit repo-default write tokens. Job-level blocks
(publish OIDC/release, CodeQL SARIF upload) override where elevation
is required.
…ch protection

- Add ci-eslint/ci-biome facade jobs (ES Lint CI / Biome CI) as single
  stable required-check names immune to matrix/node-version churn.
  if: always() + explicit result validation so upstream failures FAIL
  the facade instead of skipping it (skipped satisfies requirements).
- Drop paths-ignore from security.yml pull_request: trigger-level path
  filters suppress the check entirely on docs-only PRs, which would
  strand required status checks at 'Expected' forever.
@shaunburdick
shaunburdick merged commit 9f98cef into main Aug 23, 2026
14 checks passed
@shaunburdick
shaunburdick deleted the 001-biome-config branch August 23, 2026 17:04
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.

2 participants