npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@berachain/biome-config

v0.1.0

Published

Shared Biome configuration (config.json) and custom GritQL plugins that enforce this repo's coding standards.

Readme

@berachain/biome-config

Custom GritQL plugins for Biome plus the shared Biome configuration that this repo and its siblings extend. The config (config.json, exported as @berachain/biome-config/biome) carries the formatter, import ordering, the tuned linter rules and the plugin registrations, so a repo picks all of it up from a single extends entry. Each plugin is a .grit file under plugins/ that matches an AST pattern, reports a diagnostic through Biome's linter, and — on Biome ≥ 2.5 — can attach an autofix.

Requires Biome ≥ 2.5 (this repo pins 2.5.14). Below that the config is rejected outright — linter.rules.preset does not exist in 2.4 — and plugin fixes (the rewrite operator + fix_kind) are a 2.5 feature. @biomejs/biome >=2.5.0 is declared as a peer dependency, so a consumer below the floor gets an unmet peer warning from pnpm.

prefer-function-declarations is registered by the shared config at Grit severity error, so it applies repo-wide as soon as a config extends it. The package is private and ships no build output; it exists to hold the shared configuration, the .grit files and their tests.

Shared configuration

config.json is the reusable half of a repo's Biome setup: formatter, import ordering (assist.organizeImports), the tuned linter rules, the plugin registrations and the framework-file filename exemption. It is exported as @berachain/biome-config/biome, so any repo can extend it instead of copying settings around:

// consumer-repo/biome.json
{
  "$schema": "https://biomejs.dev/schemas/2.5.14/schema.json",
  "root": true,
  "extends": ["@berachain/biome-config/biome"]
}

That is the whole setup: the plugins come with the config. The root biome.json in this repo is the reference consumer — it extends the shared config and keeps only what is local to it (the files.includes excludes, the vcs block, repo-specific noRestrictedImports paths and local overrides).

Four things make this work, all verified against Biome 2.5.14:

  • The shared config sets "root": false. Biome errors with "Found a nested root configuration, but there's already a root configuration" otherwise.
  • The shared config is not named biome.json. Biome's scanner discovers any biome.json in the tree as a nested config for that folder and resolves its own relative paths from there, so a ./node_modules/... plugin entry inside a file named biome.json dies with "Cannot read file". config.json stays out of the scanner.
  • A plugin path is resolved from the config that extends the shared one, so ./node_modules/@berachain/biome-config/plugins/<name>.grit is the form that works — own-relative ./plugins/<name>.grit and bare package specifiers both fail. This assumes the package is installed next to the extending config (i.e. in the repo root's node_modules).
  • A shared config cannot extend anything in turn, so keep it dependency-free.

Everything else merges as you would expect: the consumer's linter.rules and overrides are deep-merged on top of the shared ones (a consumer rule turns one rule off; it does not replace the block).

Which rules actually run

The rules come from the consumer's Biome binary, not from this config. The config only turns rules on and off by name, so preset: "recommended" means "whatever recommended is in the version that is running" — a newer Biome enables its newer recommended rules on top of these settings. Verified against 2.4.16, 2.5.0, 2.5.8 and 2.5.14:

  • Unknown keys are fatal. A Biome older than a rule key in this config (or a newer one that renamed or dropped a key) exits with Found an unknown key <key>, lists the known keys and lints nothing. 2.4.16 against this config dies on preset. That is also the maintenance rule: only use keys that exist at the peer floor (2.5.0), otherwise every consumer below the newer version breaks.
  • $schema is editor metadata. The URL is never fetched — a nonsense URL or a wrong-major one changes nothing. The version string in the config that is entered (the consumer's root, not an extended one) is compared with the CLI at major.minor level: a mismatch prints an info plus a biome migrate suggestion, and nothing fails. Patch drift is not reported at all.
  • Patch drift still changes results. The same config on 2.5.0 reported 16 errors where 2.5.14 reported 0 on an identical tree, so the version check is not a behaviour guarantee. Repos get deterministic output by pinning an exact Biome themselves; the >=2.5.0 peer is a compatibility floor, not a contract.

What stays in the consuming repo

Nothing repo-specific belongs in the shared config: files.includes excludes, vcs, extra noRestrictedImports entries and local overrides all live in the consuming repo's biome.json. The @berachain/* entries in the import groups are harmless in repos that do not use those packages: the groups simply never match.

Consuming the package from another repo

The package is private, so today a consumer picks one of:

  • Publish it (drop "private": true, bump the version) and pnpm add -D @berachain/biome-config, like @berachain/graphql/config.
  • Link the local clone for local work: pnpm add -D @berachain/biome-config@file:../<clone>/packages/biome-config.

Biome resolves @berachain/biome-config/biome from the working directory it is invoked in (node_modules lookup, climbing parent directories), so running the CLI from a nested workspace folder also works.

Plugins

| Plugin | Skill rule | Severity | Fix | What it flags | | --- | --- | --- | --- | --- | | prefer-function-declarations.grit | function-declarations | error | unsafe (partial) | An arrow function assigned to a const (a named function should be a function declaration). |

prefer-function-declarations

Prefer function declarations over arrow functions. Arrow functions should only be used as inline callbacks.

Flagged (arrow assigned to a const):

const foo = () => {};                 // -> function foo() {}
const ret = (x: number): number => x; // typed / return-typed forms too
const id = <T,>(value: T): T => value; // generics
const load = async () => fetchThing(); // async
export const Comp = () => <div />;     // -> export function Comp() { return <div />; }

Allowed (the rule only targets named function definitions):

function foo() {}                       // a real function declaration
items.map((x) => x * 2);                // inline callback
useEffect(() => {}, []);                // inline callback
const onClick = useCallback(() => {}, []); // value is a call, not an arrow
const handlers = { onClick: () => {} }; // object-property arrow

The detection matches the arrow node directly ($value <: arrow_function()), so typed, return-typed, generic and async arrow forms are all caught.

Fix (unsafe, Biome ≥ 2.5): the common forms are rewritten into a function declaration — block bodies are kept, expression bodies are wrapped in { return … }, and async is preserved:

const c = (z) => z * 2;               // -> function c(z) { return z * 2; }
const b = async () => { await x(); }; // -> async function b() { await x(); }

The fix is unsafe (applied only with biome check --write --unsafe) because arrow → function changes this/arguments binding and hoisting. Typed (const x: T = …), generic (<T,>() => …) and return-typed ((): T => …) arrows are detection-only — still flagged, but not auto-fixed, because the rewrite patterns can't decompose them and a naive fix would drop the type.

Known limitation: only const declarations are matched. let/var arrow assignments are not flagged because GritQL treats let/var as keywords inside a code pattern, so a `let $name = $value` pattern never matches. Assigning an arrow to let/var for a named function is rare and discouraged anyway. This is pinned by a test so the behaviour is noticed if a future Biome release changes it.

Adding a plugin

The bundled plugins are registered by the shared config.json, so they apply wherever it is extended. A new plugin is added the same way — put the .grit file in plugins/ and add its ./node_modules/@berachain/biome-config/plugins/<name>.grit path to the shared plugins array:

{
  "plugins": [
    "./node_modules/@berachain/biome-config/plugins/prefer-function-declarations.grit",
    "./node_modules/@berachain/biome-config/plugins/<new-plugin>.grit"
  ]
}

A consumer that wants a plugin only on part of its tree registers it in its own config with includes instead:

{
  "plugins": [
    {
      "path": "./node_modules/@berachain/biome-config/plugins/prefer-function-declarations.grit",
      "includes": ["src/actions/**"]
    }
  ]
}

The Grit files register diagnostics at error severity, so new violations fail the --diagnostic-level=error pre-commit/CI gate.

Tests

Tests live in test/ and run as the biome-config project in the root vitest config. Run them from the repo root — the project's include globs are root-relative, so pnpm --filter (which changes the working directory) finds no test files:

pnpm test packages/biome-config             # path filter, from the repo root
pnpm exec vitest run --project biome-config # this project only, single run

Each test calls lintSource / fixSource, which write the source to a temporary .tsx file and run the workspace-pinned Biome CLI against it with only the plugin under test enabled (every built-in rule disabled). lintSource returns the parsed plugin diagnostics; fixSource runs --write --unsafe and returns the rewritten file. Both exercise the real Biome GritQL engine rather than mocking it.

Adding a new plugin

  1. Write plugins/<name>.grit. Start the file with a comment block describing the rule, the cases it flags/allows, and any limitations.
  2. Add a test/<name>.unit.test.ts test that calls lintSource({ source, plugin: "<name>.grit" }) with both positive (flagged) and negative (allowed) cases.
  3. Document it in the Plugins table above.

Notes on Biome's GritQL subset

Biome supports a limited subset of GritQL. Verified against Biome 2.5.14 while building prefer-function-declarations.

Works:

  • Backtick code patterns: `const $name = $value`.
  • Bare node matchers in snake_case (arrow_function()) or Biome CST PascalCase (JsArrowFunctionExpression()).
  • or { … } alternations (first matching branch wins — no duplicate diagnostics), the <: match operator, predicate definitions, and register_diagnostic(span = …, message = …, severity = …, fix_kind = …).
  • The rewrite operator (=>) for fixes — but fix_kind and applicable plugin fixes need Biome ≥ 2.5 (on 2.4.x fix_kind fails to compile and rewrites are silently no-ops). The default fix kind is unsafe.

Does not work, and shaped the implementation:

  • Custom diagnostic names/categories: register_diagnostic accepts no category/name/code argument (even on 2.5.14), so every plugin diagnostic is reported under the hardcoded plugin category (biome(plugin)). The rule name is put at the front of the message instead.
  • Named field access such as JsVariableDeclarator(initializer = $init) fails to compile.
  • `let …` / `var …` code patterns silently match nothing (keyword clash with GritQL's own let).

Why only one function rule is enforced here

The coding standards list three function rules. Only function-declarations is mechanically enforceable as a GritQL plugin:

  • The object-arguments rule ("use a single object argument instead of many positional params") is already covered by Biome's built-in complexity/useMaxParams rule (configured to max: 3 in the shared config.json). A dedicated plugin would duplicate it, and counting parameters in GritQL is awkward, so it is intentionally not reimplemented here.
  • The callback-naming rule (onXxx for props, handleXxx for local handlers) requires semantic knowledge — whether an identifier is a prop, and whether a handler wraps an onXxx callback — that cannot be expressed in Biome's pattern-only GritQL subset. It remains a review-time convention.

Agent-oriented details: AGENTS.md.