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

selo-eslint-raiz

v0.1.0

Published

selo rule pack — three core ESLint rules wrapped for the selo contract (no-empty, no-useless-catch, object-curly-newline). Ships a shimEslintRule() helper so the same pattern can be applied to any other ESLint rule.

Readme

selo-eslint-raiz

A selo rule pack that wraps three core ESLint rules into the selo contract, plus a generic shimEslintRule() helper so you can wrap any other ESLint rule the same way. Companion to @guilhermesilveira/selo.

Rules

| Rule id | Wraps | What it catches | |---|---|---| | eslint/no-empty | core no-empty (with allowEmptyCatch: false) | empty {} blocks, including empty catch clauses | | eslint/no-useless-catch | core no-useless-catch | catch (e) { throw e; } patterns that hide nothing and serve no purpose | | eslint/object-curly-newline-imports | core object-curly-newline (with ImportDeclaration: 'never') | multi-line import { ... } declarations |

All three are count rules under the selo contract: each violation produces one value: 1 measurement. Histograms aren't meaningful for them; ratchet works on violationsVsGoal (count) only.

Install

npm install --save-dev @guilhermesilveira/selo selo-eslint-raiz

Use

In selo.config.mjs:

import eslintRaiz from 'selo-eslint-raiz';

export default {
  packs: [eslintRaiz],
  rules: {
    'eslint/no-empty':                     { goal: 0 },
    'eslint/no-useless-catch':             { goal: 0 },
    'eslint/object-curly-newline-imports': { goal: 0 },
  },
};

For count rules, goal: 0 is the natural target — fewer violations is always better. Goal could be set to a non-zero number if you want to land the rule with a tolerance budget; the ratchet will tighten down toward zero from the seeded current.

How the shim works

Each rule in this pack is built by shimEslintRule({...}), which spins up an isolated ESLint Linter, configures only the wrapped rule, runs the file through it, and emits one selo measurement per violation. The mechanism in one paragraph:

  1. selo's engine parses the file and hands the rule a SeloFile with path, source, and the parsed AST.
  2. The shim ignores the AST (re-parsing is cheap; ESLint will do it again with @typescript-eslint/parser) and calls linter.verify(source, {...}) with a tiny flat config that loads the wrapped rule and its options.
  3. Each LintMessage whose ruleId matches the wrapped rule becomes a SeloMeasurement with value: 1, the line number, and the rendered ESLint message in data.message.
  4. selo's seal-message rendering takes over from there — the message in data flows into the rule's seal template at offender-listing time.

Importantly, the shim does not load the host project's ESLint config. The wrapped rule runs in isolation with the options the shim authored. This keeps selo and ESLint deliberately decoupled — you don't have to keep two configs in sync, and the verdict is reproducible across machines.

Adding a new ESLint rule

Each of the three rule files in src/rules/ is a single call to shimEslintRule(). To add a new core ESLint rule, copy one of them:

// src/rules/eslintNoDebugger.ts
import { shimEslintRule } from '../lib/shim.js';

export const eslintNoDebugger = shimEslintRule({
  id: 'eslint/no-debugger',
  description: 'Forbid `debugger` statements.',
  unitLabel: 'debuggers',
  seal: '`debugger` at line {{line}}. Remove it before committing.',
  eslintRuleId: 'no-debugger',
});

Then export it from src/index.ts:

import { eslintNoDebugger } from './rules/eslintNoDebugger.js';

export const seloEslintRaiz: SeloRulePack = {
  // ...
  rules: {
    // ...
    'eslint/no-debugger': eslintNoDebugger,
  },
};

That's it — no extra wiring, no schema declaration. The seal message gets {{line}}, {{message}}, and {{ruleId}} from the underlying ESLint diagnostic.

Wrapping non-core ESLint rules

The shim only registers the rule, not the plugin that defines it. To wrap a community-plugin rule, the pattern is the same but you need to load the plugin into the shim's Linter instance. That's a small extension to shimEslintRule() (add a plugin + pluginName option, register it in the verify() config). This is intentionally out of scope for eslint-raiz — keeping this pack core-only avoids dragging external plugin deps into selo's tree. If you need to wrap a plugin rule, fork the helper or build a separate selo-eslint-<plugin>-raiz pack.

Releasing

Manual SemVer release flow. See @guilhermesilveira/selo's release notes for the engine-releases-first ordering — when @guilhermesilveira/selo's contract changes, the engine ships first, then this pack bumps its peer range and follows.

# 1. Move [Unreleased] in CHANGELOG.md under a new
#    `## [<version>] — YYYY-MM-DD` heading.
# 2. If the engine bumped, update peerDependencies."@guilhermesilveira/selo"
#    in package.json.
# 3. npm version patch        # 0.0.1 → 0.0.2 (or `minor` / `major`)
# 4. git push --follow-tags
# 5. npm publish               # one-time `npm login` first

The prepublishOnly script gates publishing on a clean build + tests + lint, so a broken state can't ship.


Layout

src/
  lib/shim.ts                       shimEslintRule() — the wrapping helper
  rules/eslintNoEmpty.ts            shim for `no-empty`
  rules/eslintNoUselessCatch.ts     shim for `no-useless-catch`
  rules/eslintObjectCurlyNewline.ts shim for `object-curly-newline` (imports)
  index.ts                          pack export
tests/
  helpers.ts                        fixtureFile() — parse + set parents
  shim.test.ts                      shim helper itself
  eslint*.test.ts                   one focused test per rule