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

@2h2d/oxlint-config

v0.1.1

Published

Shared Oxlint rules and configuration for 2h2d repositories

Readme

@2h2d/oxlint-config

Shared Oxlint rules and strict configuration for 2h2d TypeScript and JavaScript repositories.

The package combines:

  • custom syntax and scope rules under the 2h2d/ namespace;
  • selected native Oxlint rules;
  • one versioned policy consumed by regular Oxlint and Vite+ projects.

Install

Install the package and its exact supported Oxlint version as development dependencies:

npm install --save-dev --save-exact @2h2d/[email protected] [email protected] [email protected]

Oxlint configuration

Create oxlint.config.ts:

import { strictConfig } from "@2h2d/oxlint-config";
import { defineConfig } from "oxlint";

export default defineConfig({
  extends: [strictConfig],
});

The inherited configuration enables the TypeScript, Unicorn, Oxc, and Promise plugins; the native correctness category; the shared rules; built-in globals; type-aware linting and type checking; and unused suppression reporting. Add project-specific rules or overrides after extends.

The package requires Node.js 22.19 or newer, matching the generated 2h2d TypeScript projects.

Vite+ configuration

Import the same rule map into the Vite+ lint configuration:

import { strictRules } from "@2h2d/oxlint-config/strict-rules";
import { defineConfig } from "vite-plus";

export default defineConfig({
  lint: {
    plugins: ["typescript", "unicorn", "oxc", "promise"],
    jsPlugins: [
      {
        name: "2h2d",
        specifier: "@2h2d/oxlint-config/plugin",
      },
    ],
    rules: strictRules,
    options: {
      reportUnusedDisableDirectives: "error",
      typeAware: true,
      typeCheck: true,
    },
  },
});

Custom rules

The strict preset enables these custom rules as errors:

  • 2h2d/no-broad-dictionary-values
  • 2h2d/no-broad-object-parameters
  • 2h2d/no-module-mocking
  • 2h2d/no-typebox-unsafe
  • 2h2d/require-narrow-suppression-directives
  • 2h2d/require-promise-rejection-parameter

The suppression-directive rule requires lint suppressions to use disable-line or disable-next-line, name exactly one rule, and include an explanation after --. Native typescript/ban-ts-comment separately bans @ts-ignore and @ts-nocheck while allowing @ts-expect-error with a meaningful description. Both explanations require at least ten characters. reportUnusedDisableDirectives: "error" is a root configuration option supplied by the inherited strict configuration.

The module-mocking rule prohibits mock, doMock, and unstable_mockModule calls on Jest and Vitest APIs. Tests replace dependencies through production interfaces or faithful implementations. Native restricted-method rules were not adopted because loading their framework plugins also activates unrelated correctness-category rules, and loading both produces duplicate diagnostics.

The TypeBox rule rejects Unsafe calls imported from typebox, including named, aliased, default, and namespace import forms. Prefer TypeBox builders. When builders cannot express the schema, use const native JSON Schema and derive the static type with Static<typeof schema>; although TypeBox does not strongly check the native schema's keywords, deriving from it still prevents an independently declared static type from drifting away. Use Unsafe with a narrow explained suppression only when neither representation can express the required invariant.

The broad-object-parameter rule rejects the lowercase object contract on function inputs, including local generic aliases that resolve to it, while allowing meaningful generic constraints such as Value extends object. Suppress it narrowly when “any non-primitive” is the exact intended API. Do not replace an accurate object contract with a one-position generic such as <Value extends object>(value: Value): void; native typescript/no-unnecessary-type-parameters rejects that generic because it does not relate or preserve type information.

The dictionary rule rejects direct value contracts based on object and semantically empty contracts hidden behind intersections or utility types. Native typescript/no-empty-object-type owns explicit {} and empty declaration diagnostics, while typescript/no-explicit-any owns explicit any. Use unknown when values are genuinely uncertain and narrow them before use.

The Promise rejection parameter rule requires inline and locally resolvable .catch callbacks, and the rejection callback passed to .then, to declare the rejection reason. It closes the syntax gap between Promise callbacks and native preserve-caught-error without guessing whether a particular logging or diagnostic sink is adequate. Because Oxlint JavaScript plugins do not receive type information, unrelated APIs using catch or then can use a narrow explained suppression.

Native rules

The strict rule map explicitly enables these native Oxlint rules. The exported strict configuration additionally enables Oxlint's native correctness category; inspect the effective version-pinned set with oxlint --print-config <file>.

{
  "array-callback-return": "error",
  "eqeqeq": ["error", "always", { "null": "ignore" }],
  "no-case-declarations": "error",
  "no-constructor-return": "error",
  "no-extend-native": "error",
  "no-new-func": "error",
  "no-new-wrappers": "error",
  "no-proto": "error",
  "no-prototype-builtins": "error",
  "no-var": "error",
  "oxc/misrefactored-assign-op": "error",
  "oxc/no-accumulating-spread": "error",
  "preserve-caught-error": ["error", { "requireCatchParameter": true }],
  "promise/no-callback-in-promise": "off",
  "promise/no-multiple-resolved": "error",
  "promise/valid-params": "off",
  "typescript/ban-ts-comment": [
    "error",
    {
      "minimumDescriptionLength": 10,
      "ts-check": false,
      "ts-expect-error": "allow-with-description",
      "ts-ignore": true,
      "ts-nocheck": true
    }
  ],
  "typescript/consistent-type-assertions": ["error", { "assertionStyle": "never" }],
  "typescript/method-signature-style": ["error", "property"],
  "typescript/no-empty-object-type": "error",
  "typescript/no-explicit-any": "error",
  "typescript/no-floating-promises": [
    "error",
    {
      "allowForKnownSafeCalls": [
        {
          "from": "package",
          "name": ["describe", "it", "test"],
          "package": "node:test"
        }
      ],
      "ignoreVoid": false
    }
  ],
  "typescript/no-import-type-side-effects": "error",
  "typescript/no-invalid-void-type": "error",
  "typescript/no-misused-promises": "error",
  "typescript/no-non-null-assertion": "error",
  "typescript/no-require-imports": "error",
  "typescript/no-unnecessary-type-parameters": "error",
  "typescript/no-unsafe-argument": "error",
  "typescript/no-unsafe-assignment": "error",
  "typescript/no-unsafe-call": "error",
  "typescript/no-unsafe-enum-comparison": "error",
  "typescript/no-unsafe-function-type": "error",
  "typescript/no-unsafe-member-access": "error",
  "typescript/no-unsafe-return": "error",
  "typescript/only-throw-error": "error",
  "typescript/prefer-promise-reject-errors": [
    "error",
    {
      "allowEmptyReject": false,
      "allowThrowingAny": true,
      "allowThrowingUnknown": true
    }
  ],
  "typescript/return-await": ["error", "error-handling-correctness-only"],
  "typescript/switch-exhaustiveness-check": [
    "error",
    {
      "allowDefaultCaseForExhaustiveSwitch": false,
      "considerDefaultExhaustiveForUnions": false
    }
  ],
  "typescript/use-unknown-in-catch-callback-variable": "error",
  "unicorn/no-accessor-recursion": "error",
  "unicorn/no-array-fill-with-reference-type": "error",
  "unicorn/no-new-buffer": "error",
  "unicorn/prefer-node-protocol": "error",
  "oxc/double-comparisons": "off",
  "oxc/erasing-op": "off",
  "oxc/number-arg-out-of-range": "off",
  "oxc/uninvoked-array-callback": "off",
  "unicorn/no-empty-file": "off",
  "unicorn/no-new-array": "off",
  "unicorn/no-single-promise-in-promise-methods": "off",
  "unicorn/no-thenable": "off",
  "unicorn/no-useless-spread": "off",
  "unicorn/prefer-string-starts-ends-with": "off"
}

Switch cases containing lexical declarations use explicit blocks so their bindings cannot leak into the switch-wide lexical environment. Constructors may return early without a value but must not replace their initialized instance. Intentional singleton, proxy, cache, or other instance-substitution behavior requires an explained suppression. Function-scoped var declarations are prohibited in favor of let and const; TypeScript ambient declarations remain valid. Native global prototypes must not be extended. Intentional polyfills or runtime patches require a narrow explained suppression because they alter process-wide behavior. Boxed primitive constructors are prohibited because they introduce object identity and truthiness; intentional wrapper identity requires an explained suppression instead of applying the fixer. The deprecated magic __proto__ accessor is prohibited in favor of explicit Object or Reflect prototype operations. Null-prototype object literals remain valid; intentional data fields named __proto__ require an explained suppression. Direct calls to inherited object prototype methods are prohibited because null-prototype or externally shadowed objects make them unsafe; prefer Object.hasOwn for ownership checks. Global CommonJS require calls are prohibited in ESM projects; explicit local createRequire bindings remain valid, while intentional .cjs boundaries require an explained suppression. Incomplete compound-assignment refactors such as total += total + amount are rejected; intentional recurrence formulas can use an ordinary assignment or an explained suppression. Accumulating spread is rejected because repeated full copies produce quadratic work. Compliance must preserve caller-owned seeds and intentional snapshots; explain those immutable contracts rather than replacing them blindly with mutation. Inline Promise executors must not reach a second resolve or reject call after settlement. Recursive access through the same getter or setter is rejected. Dynamic accessors that replace themselves before the reported access require an explained suppression. Filling every array position with the same obvious object reference is rejected. Intentional shared immutable sentinels and custom cloning fill methods require an explained suppression. The deprecated argument-overloaded new Buffer API is prohibited in favor of explicit allocation or conversion methods. The native rule currently recognizes only the global Buffer binding. Node.js built-in module specifiers must use the explicit node: protocol. Intentional build-time aliases for bare built-in names require an explained suppression because their resolution differs.

The strict map explicitly disables twelve rules inherited from the native correctness category. Syntax-only comparison algebra is not sound for values such as NaN or objects with coercion semantics. Arithmetic involving zero can preserve NaN, infinity, negative zero, or operand side effects instead of collapsing to the numeric value 0. Obsolete number-formatting limits reject precision values permitted by modern JavaScript. Function values passed to array methods such as fill are not necessarily callbacks. Spread can intentionally snapshot an iterable or convert sparse slots into dense undefined values. Empty committed files can be meaningful artifacts; single-argument new Array(length) has intentional sparse-array semantics; a one-element Promise combinator can preserve aggregation shape and Promise identity; custom thenables are a standard interoperability contract; and anchored regular expressions are not always equivalent to startsWith or endsWith. Native promise/no-new-statics is active through the correctness category. promise/valid-params remains disabled because it rejects valid parameterless forwarding calls and can mistake unrelated then, catch, and finally methods for Promise operations. promise/no-callback-in-promise remains disabled because it relies on callback names, can be bypassed by renaming, and rejects legitimate Promise-to-callback adapters.

The test suite pins the exact correctness-category inventory for every loaded native plugin. Oxlint upgrades fail until each added, removed, or reclassified rule is reviewed explicitly.

Every catch must bind its failure, and replacement built-in errors must preserve that value as their cause. Promise-style rejection callbacks must likewise bind their rejection reason. Whether a caught failure should be logged or recorded is a review decision rather than a custom lint heuristic.

Every non-const type assertion and postfix non-null assertion is prohibited. as const remains allowed. Empty {} and unsafe Function contracts are prohibited. Object-type callables use function-property syntax so strictFunctionTypes checks parameter variance. void promise is not accepted as Promise rejection handling, and a Promise returned from a try block must be awaited when rejection would otherwise bypass local error handling. Only the describe, it, and test declarations from node:test are exempt from floating-Promise enforcement because the test runner observes their Promises.

Generic parameters must relate multiple positions or preserve information through an output. Do not use a one-position generic merely to disguise a broad input contract.

Promise.reject requires an Error when the rejection type is known. An unknown or externally typed any reason may be forwarded unchanged so the lint policy does not force wrapping that alters failure identity. Explicit any remains prohibited at its source.

Rule namespaces

Rules retain the namespace of their implementation:

  • native TypeScript rules use configuration IDs such as typescript/no-explicit-any and are displayed as typescript(no-explicit-any);
  • native ESLint-compatible rules use IDs such as preserve-caught-error and are displayed as eslint(preserve-caught-error);
  • rules implemented by this package use IDs such as 2h2d/no-broad-object-parameters and are displayed as 2h2d(no-broad-object-parameters).

Importing a native rule through strictRules does not move it into the 2h2d namespace.

Rule design

  • Parse uncertain values at their I/O boundary.
  • Declare callable object-type members as function properties so their parameters are checked contravariantly.
  • Derive static types from their runtime schemas instead of pairing them through Type.Unsafe.
  • Propagate unexpected failures and preserve their original causes.
  • Keep promises observable and use exhaustive union handling.
  • Use named contracts for meaningful inputs and outputs.
  • Use unknown for genuinely uncertain dictionary values and narrow each value before use.
  • Represent data with recursive JsonValue and JsonObject only after establishing that it is JSON.
  • Replace dependencies through production interfaces rather than module-loader mocks.
  • Apply policy to every committed TypeScript and JavaScript file without special directories for vendored, test, or tooling code.
  • Prefer a narrow explained suppression over distorting a contract, adding a pass-through helper, or deleting useful test coverage.

Compatibility

Oxlint JavaScript plugins are currently alpha and outside normal semantic-versioning guarantees. This package pins and tests Oxlint and @oxlint/plugins 1.79.0 with oxlint-tsgolint 7.0.2001. Update those versions together and validate the package-consumer integration test before release.

Development

npm install
npm run check
npm test
npm run pack:dry

npm test builds the package before running rule, preset, package-export, and Oxlint consumer tests.

Packaging

.github/npm-package-files is the authoritative package-content allowlist used by the local release command and both CI jobs. Update it whenever the intended published file set changes.

Release staging

Repository setup:

  1. Configure npm trusted publishing for 2h2d-co/oxlint-config using .github/workflows/publish.yml and the npm-publish environment.
  2. Restrict that GitHub environment to v* tags without a deployment reviewer or administrator bypass.
  3. Protect main with code-owner review and protect v* tags from unauthorized changes while retaining the repository-administrator release path.
  4. Replace .github/release-signers if release commits use a different SSH signing key.

Release flow:

  1. Run npm run release -- X.Y.Z from a clean, synchronized main.
  2. Inspect the signed release commit and lightweight tag.
  3. Push them atomically with git push --atomic origin main vX.Y.Z.
  4. Approve the staged package after CI verifies its source, signature, digest, provenance, and contents.

Attribution

Selected rules are adapted from dmmulroy/anti-slop under the MIT License. See THIRD_PARTY_NOTICES.md and LICENSES/anti-slop-MIT.txt.