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

@thasmorato/eslint-config

v3.0.0

Published

My EsLint configurations

Readme

ESLint config

Configs compartilhados de ESLint, em flat config, para Node, React e Next.js.

O que vem junto

  • Base neostandard (sucessor do eslint-config-standard);
  • TypeScript via typescript-eslint;
  • React, React Hooks e JSX a11y;
  • Prettier, acoplado — a formatação vem junto, sem .prettierrc no projeto;
  • Ordenação de imports (simple-import-sort) e higiene de import (import-x);
  • Guarda-corpos de complexidade e clean code — ver a seção abaixo.

Requisitos

  • ESLint ^9 — este pacote não roda em ESLint 10 ainda, ver ADR-0001;
  • Node ^18.18 || ^20.9 || >=21.1.

Setup

npm i -D eslint @thasmorato/eslint-config

O ESLint procura por eslint.config.js na raiz. Não use mais .eslintrc.json.

Node.js

// eslint.config.js
import node from '@thasmorato/eslint-config/node'

export default node

React (sem Next.js)

// eslint.config.js
import react from '@thasmorato/eslint-config/react'

export default react

React (com Next.js)

O preset next é um fragmento: ele precisa ser composto com next/core-web-vitals. Sozinho ele falha, e isso é de propósito.

// eslint.config.js
import coreWebVitals from 'eslint-config-next/core-web-vitals'
import next from '@thasmorato/eslint-config/next'

export default [...next, ...coreWebVitals]

O eslint-config-next (v15+) já exporta flat config — não precisa de FlatCompat.

Ele registra os plugins react, react-hooks e jsx-a11y, e o flat config lança Cannot redefine plugin se dois blocos registram o mesmo plugin. Por isso o preset next não registra nenhum dos três: ele só ajusta as regras deles e deixa o Next ser o dono. Ver ADR-0005.

Ajustando no projeto

Flat config é um array; para sobrescrever, acrescente um bloco no fim:

import node from '@thasmorato/eslint-config/node'

export default [
  ...node,
  {
    rules: {
      'max-lines-per-function': ['warn', { max: 80 }],
    },
  },
]

Guarda-corpos de clean code

A severidade segue uma linha só: defeito é error, cheiro é warn. Um cheiro aparece no editor sem quebrar um build que já estava verde.

| Intenção | Regra | Sev | Valor | |---|---|---|---| | Funções pequenas | max-lines-per-function | warn | 50 | | Arquivo não vira God object | max-lines | warn | 300 | | Uma coisa só | max-statements | warn | 20 | | Poucos argumentos | max-params | warn | 4 | | Complexidade ciclomática | complexity | warn | 10 | | Complexidade cognitiva | sonarjs/cognitive-complexity | warn | 15 | | Aninhamento | max-depth | warn | 3 | | Callback hell | max-nested-callbacks | warn | 3 | | Níveis de abstração | sonarjs/no-nested-functions | warn | 3 | | I/O serializado em loop | no-await-in-loop | warn | — | | Sem efeito colateral escondido | no-param-reassign | error | props | | Nunca engolir erro | no-empty, sonarjs/no-ignored-exceptions | error | — | | DRY | sonarjs/no-identical-functions | warn | — |

Em arquivos de teste (*.spec.*, *.test.*, tests/, __tests__/) os limites de tamanho e de duplicação ficam desligados: um describe é uma função longa por natureza e fixture repete de propósito.

Sobre "validação de O notation"

Não existe. Complexidade assintótica é estaticamente indecidível — nenhum linter a calcula, e o eslint-plugin-complexity que aparece nas buscas está sem manutenção desde 2022.

O que este config entrega são os proxies tratáveis: max-depth e max-nested-callbacks pegam o aninhamento que costuma indicar custo polinomial, no-await-in-loop pega I/O serializado, e sonarjs/cognitive-complexity pega o que é caro de segurar na cabeça. É honesto chamar isso de guarda-corpo de complexidade, não de análise de Big-O.

Migrando da v1

A v2 é breaking em todos os eixos:

| v1 | v2 | |---|---| | .eslintrc.json com extends | eslint.config.js com import | | eslint@^8 | eslint@^9 | | eslint-config-standard | neostandard | | regras import/* | regras import-x/* | | CommonJS | ESM ("type": "module") |

Se você tem // eslint-disable-next-line import/no-duplicates espalhado, o prefixo virou import-x/.

Decisões

Os porquês estão em docs/adr/:

  • ADR-0001 — por que ESLint 9 e não 10
  • ADR-0002 — por que neostandard
  • ADR-0003 — por que import-x sem as regras de resolução
  • ADR-0004 — por que o Prettier segue acoplado
  • ADR-0005 — por que o preset next não roda sozinho

Desenvolvimento

npm test           # node:test — linta fixtures via API do ESLint e afirma os ruleId
npm run lint       # o pacote se linta com o preset que publica (dogfood)
npm run test:consumer  # empacota, instala num projeto temporário e linta de lá

Release

Publicação automática no push pra main, a partir do tipo do commit (Conventional Commits):

| Commit | Bump | Use quando | |---|---|---| | fix: refactor: perf: | patch | corrige o config sem fazer regra nova disparar | | feat: | minor | regra nova entrando como warn | | feat!: / BREAKING CHANGE: | major | regra nova como error, warnerror, preset muda de forma | | chore: docs: ci: test: style: | — | sem release |

A convenção do meio é o que mantém o ^ seguro: regra nova nasce warn; promover pra error é major. Num config compartilhado, uma regra nova que dá error quebra o build de quem não mudou uma linha de código — por isso ela não pode entrar numa minor.

O bump vem de scripts/bump.js, que é função pura e tem teste (tests/bump.spec.js). O workflow roda testes, lint e o smoke test de consumidor antes de publicar, e só empurra a tag depois do publish dar certo — assim uma falha nunca deixa tag apontando pra versão que não foi ao ar.

Setup, uma vez

  1. Trusted publishing no npm — em npmjs.com, na página do pacote → Settings → Trusted Publishers, adicione: repositório ThaSMorato/eslint-config, workflow release.yml. Não é preciso criar nem guardar NPM_TOKEN.

  2. Tag inicial — o repo não tem tags. Sem uma, o primeiro run olha o histórico inteiro, encontra feat: antigos e publicaria 2.1.0. Marque o ponto de partida:

    git tag v2.0.0 && git push origin v2.0.0

    A partir daí a automação conta só o que vier depois.