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

@gabegabegabe/eslint-config

v15.0.0

Published

Gabe's eslint configs

Readme

@gabegabegabe/eslint-config

Gabe's personal ESLint configs

A collection of shareable ESLint flat configs, tuned to a specific, modern toolchain: ESLint v10 flat config, ESM, typescript-eslint strictness, and per-framework opinions. They are published for anyone to use, but make no attempt to accommodate stacks other than the author's.

The configs are assembled from small composable layers. You normally spread a single leaf (and optionally a few overlays); the layers are the building blocks underneath.

Usage

Install the package, ESLint, and the peers your chosen config needs (see Requirements):

bun add -D @gabegabegabe/eslint-config eslint globals

Then create an eslint.config.js and spread the one leaf that matches what you are building:

import config from '@gabegabegabe/eslint-config/typescript-node';

export default config;

Each leaf is a flat-config array, so add your own overrides (and any overlays) by spreading:

import config from '@gabegabegabe/eslint-config/typescript-node';
import test from '@gabegabegabe/eslint-config/test';

export default [
	...config,
	...test,
	{
		name: 'my-project/overrides',
		rules: {
			'no-console': 'off'
		}
	}
];

Which config do I extend?

Pick by what you are building. Spread exactly one leaf. There is no library/app split — ESLint does not emit, so a library and an app lint identically; environment (Node / browser / Bun) and framework are the only axes.

| You are building | Spread | | --------------------------------------------- | ---------------------- | | A Node library, CLI, or service in JavaScript | ./javascript-node | | A Node library, CLI, or service in TypeScript | ./typescript-node | | A browser library or app in JavaScript | ./javascript-browser | | A browser library or app in TypeScript | ./typescript-browser | | A React library or app in JavaScript (JSX) | ./javascript-react | | A React library or app in TypeScript (TSX) | ./typescript-react | | A Vue library or app | ./vue | | A Svelte library or app | ./svelte | | A Bun service, CLI, or app | ./bun |

Notes:

  • vue, svelte, and bun are TypeScript-only (no JavaScript variant): Vue's vue/block-lang already enforces <script lang="ts">, Svelte 5 is TypeScript-first, and Bun's purpose is running TypeScript directly. Plain-Node, browser, and React projects come in both javascript-* and typescript-* flavours because plain-JS and JSX-without-TS projects are real.
  • The TypeScript leaves enable typescript-eslint's projectService, so the type-checked rules auto-discover your nearest tsconfig.json with no extra wiring. Make sure the files you lint are covered by that tsconfig; set parserOptions.tsconfigRootDir in your own config if discovery needs a hint.
  • Inside every TypeScript leaf, type-checked rules are scoped to TS files and turned off for JS files, so a mixed .ts/.js repo (e.g. a TS project with .js config files) Just Works.

Overlays

Overlays are composed alongside a leaf. They are files-scoped and additive.

| Overlay | Compose with | Role | | --------------- | ------------ | ------------------------------------------------------------------------------------------ | | ./test | any leaf | Test-file rules for bun:test (its API mirrors Jest's) | | ./test-vitest | any leaf | Test-file rules for Vitest — Vue/Svelte SFC component tests bun:test can't transform | | ./json | any leaf | Lints .json / .jsonc / .json5 via the official @eslint/json | | ./vue-pug | ./vue | Adds <template lang="pug"> support (Pug tokenizer + Pug-aware rules) |

The test and test-vitest overlays self-scope to test files (**/*.{test,spec}.*, **/__tests__/**); their typed rules apply only to TypeScript test files when composed alongside a TypeScript leaf. bun:test is the default (./test); compose ./test-vitest in projects that also run Vitest — for example, Vue/Svelte component tests, which bun:test cannot transform.

Example configs

TypeScript Node project, with tests and JSON:

import config from '@gabegabegabe/eslint-config/typescript-node';
import json from '@gabegabegabe/eslint-config/json';
import test from '@gabegabegabe/eslint-config/test';

export default [...config, ...test, ...json];

TypeScript browser app:

import config from '@gabegabegabe/eslint-config/typescript-browser';
import test from '@gabegabegabe/eslint-config/test';

export default [...config, ...test];

React (TypeScript):

import config from '@gabegabegabe/eslint-config/typescript-react';
import test from '@gabegabegabe/eslint-config/test';

export default [...config, ...test];

Vue (with Pug templates):

import config from '@gabegabegabe/eslint-config/vue';
import pug from '@gabegabegabe/eslint-config/vue-pug';
import test from '@gabegabegabe/eslint-config/test';

export default [...config, ...pug, ...test];

Bun:

import config from '@gabegabegabe/eslint-config/bun';
import test from '@gabegabegabe/eslint-config/test';

export default [...config, ...test];

Architecture

There are three tiers.

Leaves (top-level — spread exactly one)

A leaf is a self-contained flat-config array that bakes in (a) the correct internal composition order and (b) files-scoping, so you never have to wrangle either. The leaves are javascript-node, typescript-node, javascript-browser, typescript-browser, javascript-react, typescript-react, vue, svelte, and bun.

For example, typescript-node composes (left → right, later overrides earlier):

base → node → javascript → typescript → typescript-disable-type-checked (JS-scoped)

Overlays (top-level — compose alongside a leaf)

test, test-vitest, json, and vue-pug (see Overlays). Each is files-scoped so it only touches the files it should.

Layers (./layers/* — power-user building blocks)

The primitives the leaves are built from: ./layers/base, ./layers/javascript, ./layers/typescript, ./layers/typescript-disable-type-checked, ./layers/browser, ./layers/node, ./layers/bun, ./layers/vue, ./layers/vue-typescript, ./layers/react, and ./layers/svelte. Compose these yourself only if no leaf fits. The root (.) export aliases ./layers/base.

Conventions

When adding or changing a config, follow these invariants:

  1. Defer to each plugin's upstream recommended (and strict/stylistic) config first; compose this package's opinions last.
  2. Preserve the rule-promotion pattern. When a base rule has a plugin equivalent (e.g. @typescript-eslint/*, vue/*, svelte/*), disable the base rule and enable the prefixed version with the same configuration.
  3. Severity is always the numeric constants DISABLED / WARN / ERROR from lib/eslint-enforcement-codes.js — never string literals.
  4. Leaves own composition order and files-scoping so consumers never wrangle either; the ordering in each leaf is load-bearing.
  5. Be explicit; scope precisely. Type-checked rules only on TS files; test rules only on test files; framework rules only on framework files.
  6. Every flat-config object has a name for the ESLint config inspector.
  7. Tabs for indentation; no rule conflicts with Prettier.

Requirements

  • ESLint ^10 and globals ^17 are required by every config.
  • Node ^20.19.0 || ^22.13.0 || >=24 — ESLint 10's supported range, declared in engines.
  • eslint-plugin-react, eslint-plugin-react-hooks, and eslint-plugin-jsx-a11y run on ESLint 10 but do not yet declare it in their peer ranges, so the React leaves emit a harmless peer-dependency warning on install (Bun does not hard-fail on it).
  • Each leaf/overlay needs its plugin peers installed (all are optional peers, so you only install what you use):

| Config | Additional peer packages | | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | ./javascript-node, ./javascript-browser | @eslint/js, @eslint-community/eslint-plugin-eslint-comments, eslint-plugin-promise | | ./javascript-react | the above + eslint-plugin-react, eslint-plugin-react-hooks, eslint-plugin-jsx-a11y | | ./typescript-node, ./typescript-browser, ./bun | the JavaScript set + typescript-eslint, typescript | | ./typescript-react | the TypeScript set + eslint-plugin-react, eslint-plugin-react-hooks, eslint-plugin-jsx-a11y | | ./vue | the TypeScript set + eslint-plugin-vue, vue-eslint-parser | | ./svelte | the TypeScript set + eslint-plugin-svelte, svelte-eslint-parser | | ./test | eslint-plugin-jest | | ./test-vitest | @vitest/eslint-plugin | | ./json | @eslint/json | | ./vue-pug | eslint-plugin-vue-pug — use the flat-config build: eslint-plugin-vue-pug@^1.0.0-alpha |

The @eslint/js, @eslint-community/eslint-plugin-eslint-comments, and eslint-plugin-promise peers are needed by every leaf, because every leaf includes the javascript layer.

Development

bun run lint          # Lint this repo with its own configs
bun run format        # Format with Prettier (@gabegabegabe/prettier-config)
bun run format:check  # Check formatting without writing
bun run check-updates # Check for dependency updates

There are no tests; the repo lints and formats itself (prepublishOnly runs both format:check and lint). See CLAUDE.md for the internal architecture and the rules for adding or changing a config.