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

@noctcore/eslint-plugin-code-quality

v0.4.2

Published

Portable code-quality, comment-hygiene and test-discipline ESLint rules: guard clauses, deterministic time, no stray process.exit, and tests that cannot pass vacuously.

Readme

@noctcore/eslint-plugin-code-quality

Portable code-quality, comment-hygiene and test-discipline rules: catches vacuous tests, focused or untracked skipped tests, and comments that rot. Every rule keys off code and generic file-path globs, never a specific repo layout.

Docs: noctcore.github.io/eslint-plugins/packages/code-quality

Not a good fit for a team that writes explanatory step-by-step comments on purpose.

Requirements

  • ESLint 9 or newer, flat config (eslint.config.js) only.
  • configs.recommended registers the plugin and sets rule severities, nothing else. It sets no files and no parser, so it applies to whatever files the rest of your config lints. To lint TypeScript, add a files pattern and @typescript-eslint/parser, as in the quick start.

Install

bun add -D @noctcore/eslint-plugin-code-quality @typescript-eslint/parser   # or npm i -D / pnpm add -D

Quick start

// eslint.config.js
import tsParser from '@typescript-eslint/parser';
import codeQuality from '@noctcore/eslint-plugin-code-quality';

export default [
  {
    ...codeQuality.configs.recommended,
    files: ['**/*.{ts,tsx}'],
    languageOptions: { parser: tsParser },
  },
  // Optional: tune a preset rule's options.
  {
    files: ['**/*.{ts,tsx}'],
    rules: {
      'noctcore-code-quality/no-process-exit': ['error', { allowIn: ['**/scripts/**'] }],
    },
  },
];

Opt-in rules

Some rules are exported but left out of recommended. interface-prefix-i and no-template-trim-empty-ternary are house style, not correctness. The test-discipline rules in the second block need a per-project fact before they are precise, such as which files are unit tests, so each one takes its options from your project.

// eslint.config.js
export default [
  // ...the quick start's entries, then:
  {
    files: ['**/*.{ts,tsx}'],
    languageOptions: { parser: tsParser },
    rules: {
      'noctcore-code-quality/interface-prefix-i': 'error',
      'noctcore-code-quality/no-template-trim-empty-ternary': 'error',
    },
  },
  {
    files: ['**/*.{test,spec}.{ts,tsx}'],
    languageOptions: { parser: tsParser },
    rules: {
      'noctcore-code-quality/no-message-only-throw-assertion': ['error', {
        assertionHelpers: ['^expectRejectsDomainError$'],
      }],
      'noctcore-code-quality/no-sleep-in-unit-tests': ['error', {
        integrationMarkers: ['.integration.', '/e2e/'],
      }],
      'noctcore-code-quality/no-real-clock-in-unit-tests': ['error', {
        clockModules: ['**/common/clock'],
      }],
      'noctcore-code-quality/typed-mock-over-double-cast': ['error', {
        allowTargets: ['PrismaService'],
      }],
    },
  },
];

Rules

✅ on in recommended (error) · 🔘 opt-in: not on in recommended, enable it yourself · ⚙️ needs options · 🔧 --fix · 💡 suggestions · 💭 needs type info · ❌ deprecated

| Rule | Description | Preset | ⚙️ | 🔧 | 💡 | 💭 | | --- | --- | :-: | :-: | :-: | :-: | :-: | | fake-timers-must-be-restored | A test file that calls useFakeTimers() must also call useRealTimers(), so fake timers do not leak into later tests. | ✅ | | | | | | interface-prefix-i | Interface names must be prefixed with I followed by an uppercase letter. Module/global augmentations are exempt. | 🔘 | | | | | | no-bare-date-now | Disallow bare Date.now() / new Date() in business logic. Read wall-clock time through a shared clock util (nowMs() / now()) so time is mockable. | ✅ | | | | | | no-conditional-expect | Disallow expect() inside a branch, catch or loop that may not run: a skipped assertion lets a broken test pass. | ✅ | | | | | | no-elided-code-comments | Disallow comments that stand in for elided code ('// ... existing code ...', '// rest of the function unchanged', '// your code here'). They are what an agent leaves when it rewrites a file from an abbreviated draft, and the code they replaced has usually been deleted. | ✅ | | | | | | no-focused-tests | Ban focused tests (it.only / describe.only / test.only, fdescribe / fit / ddescribe) so a focused test never silently lands in CI. | ✅ | | | | | | no-historical-comments | Disallow comments that frame code relative to what it used to do or to a past incident ('before the fix', 'after the refactor', 'we used to', 'no longer'). Source comments describe the current invariant; history belongs in the commit message or PR description, where it does not rot when the code changes again. | ✅ | | | | | | no-message-only-throw-assertion | Disallow toThrow() with no argument or with only a message: any error passes, including a TypeError from a broken mock. Pin the error class. | 🔘 | | | | | | no-narration-comments | Disallow narrative comments like 'Here we...', 'Now we...', 'First, we...'. These read as step-by-step prose and add no information a future reader cannot get from the code itself. Often a tell that the comment was generated by an agent describing its own changes. | ✅ | | | | | | no-pr-reference-comments | Disallow PR/issue references in comments. They belong in commit messages and PR descriptions, where they do not rot when the repo moves, the issue tracker migrates, or the numbering changes. | ✅ | | | | | | no-process-exit | Disallow process.exit() outside bootstrap/shutdown paths and standalone CLIs. Application and service code must throw or reject so the lifecycle can shut down gracefully. | ✅ | | | | | | no-real-clock-in-unit-tests | Unit tests must not read the real clock (Date.now(), new Date()) unless the file fakes it; an offset from now (Date.now() + 60_000) is allowed. | 🔘 | | | | | | no-real-network-in-unit-tests | Unit tests must not perform real network I/O: mock the HTTP client, or move the test to an integration suite. | ✅ | | | | | | no-sleep-in-unit-tests | Unit tests must not sleep on the real clock (new Promise((r) => setTimeout(r, n)), timers/promises): fake the timers or wait for the condition. | 🔘 | | | | | | no-swallowed-assertion | Disallow assertions inside a try whose catch neither rethrows nor asserts, and .catch() handlers that swallow an expect(...).rejects/.resolves failure: the assertion fails, the error is dropped, and the test passes. | ✅ | | | | | | no-template-trim-empty-ternary | Disallow inline <template>.trim() === '' ? fallback : <template>.trim() patterns. Extract to a named utility so the expression is built once and is unit-testable in one place. | 🔘 | | | | | | no-vacuous-expect | Disallow vacuous expects (typeof checks, literal tautologies, a sole toBeDefined/toBeTruthy, a sole presence check on the render root): a test must assert behaviour that a real regression would break. | ✅ | | | | | | prefer-early-return | Prefer guard clauses (early return) over wrapping the whole function body in a multi-statement if without an else. | ✅ | | | | | | skipped-tests-need-tracking | Skipped tests (.skip / .fixme / xit / xdescribe, and unconditional node:test { skip } / { todo } / t.skip()) must carry a tracking marker (an issue URL or TODO(@owner)) on or above the line, so the debt has an owner instead of rotting silently. | ✅ | | | | | | typed-mock-over-double-cast | Disallow an object literal of jest.fn() / vi.fn() mocks cast as unknown as T: the double cast switches type checking off, so a mock of a renamed or removed method keeps passing. | 🔘 | | | | |

Severity policy

Every rule is error or off, never warn: a warning is a rule nobody obeys. See the severity policy.

Credits

no-vacuous-expect, no-conditional-expect, fake-timers-must-be-restored and no-real-network-in-unit-tests are ported from tsforge (MIT). See THIRD_PARTY_NOTICES.md.