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

@dobroslavlabs/oxlint

v0.1.4

Published

Custom Oxlint JS plugin and Ultracite-style presets for JS/TS, React, Effect, Elysia, Bun, Zod, and TanStack Router

Downloads

138

Readme

@dobroslavlabs/oxlint

Custom Oxlint JS plugin + Ultracite-style presets for JS/TS, React/JSX, Effect, Elysia, Bun, and Zod.

Quick start

bun add -d oxlint @dobroslavlabs/oxlint
// oxlint.config.ts
import { defineConfig } from "oxlint";
import recommended from "@dobroslavlabs/oxlint/recommended";

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

Or pick surfaces:

import { defineConfig } from "oxlint";
import core from "@dobroslavlabs/oxlint/core"; // JS/TS
import react from "@dobroslavlabs/oxlint/react"; // JSX/TSX + hooks
import effect from "@dobroslavlabs/oxlint/effect"; // Effect (opt-in)
import elysia from "@dobroslavlabs/oxlint/elysia"; // Elysia (opt-in)
import bun from "@dobroslavlabs/oxlint/bun"; // Bun (opt-in)
import zod from "@dobroslavlabs/oxlint/zod"; // Zod (opt-in)
import tanstackRouter from "@dobroslavlabs/oxlint/tanstack-router"; // TanStack Router (opt-in)

export default defineConfig({
  extends: [core, react, effect, elysia, bun, zod, tanstackRouter],
});

Presets

| Import | Scope | Enables | | --- | --- | --- | | @dobroslavlabs/oxlint/recommended | core + react | Default JS/TS + React set | | @dobroslavlabs/oxlint/core | all files | Plain JS/TS rules | | @dobroslavlabs/oxlint/react | React/JSX (+ hooks) | Component / JSX / hook rules | | @dobroslavlabs/oxlint/effect | all files | Effect / tagged-error rules (opt-in) | | @dobroslavlabs/oxlint/elysia | all files | ElysiaJS best-practice rules (opt-in) | | @dobroslavlabs/oxlint/bun | all files | Prefer Bun-native APIs (opt-in) | | @dobroslavlabs/oxlint/zod | all files | Zod schema rules (opt-in) | | @dobroslavlabs/oxlint/tanstack-router | all files | TanStack Router typed-nav rules (opt-in) | | @dobroslavlabs/oxlint | — | Plugin only; enable dobroslavlabs/* yourself |

Each preset sets jsPlugins: ["@dobroslavlabs/oxlint"] and turns on the matching rules. /effect, /elysia, /bun, /zod, and /tanstack-router are not included in /recommended.

Rules

Core

| Rule | Summary | | --- | --- | | require-jsdoc | Descriptive JSDoc on complex functions (defaults: statements ≥4, params ≥3, complexity ≥3) | | no-double-type-assertion | Ban nested / as unknown as assertions | | no-response-json-type-assertion | Ban asserting any *.json() call output | | no-dom-target-type-assertion | Ban casting event.target / e.target to DOM elements | | no-direct-process-env | Ban process.env (allows NODE_ENV, VITEST, JEST_WORKER_ID by default) | | no-index-barrels | Ban index.* barrel files (allow for package entrypoints) | | no-index-imports | Ban imports with an explicit /index path segment | | no-pure-re-export-files | Ban non-index files that only re-export | | no-forbidden-imports | Configurable import denylist (paths / patterns) — no-op until configured |

Most core rules accept { allow?: string[] } (path substrings — use distinctive fragments). no-direct-process-env also takes allowKeys ([] bans all keys; does not fall back to defaults).

Notes: no-index-imports only flags explicit /index paths (directory imports like ./components are allowed).

"dobroslavlabs/require-jsdoc": ["error", { minStatements: 5, minParams: 4 }],
"dobroslavlabs/no-index-barrels": ["error", { allow: ["src/index.ts"] }],
"dobroslavlabs/no-direct-process-env": ["error", { allowKeys: ["NODE_ENV", "CI"] }],
"dobroslavlabs/no-forbidden-imports": [
  "error",
  {
    paths: [{ name: "lucide-react", message: "Use Hugeicons instead." }],
    patterns: [{ regex: "^@unpic/react", message: "Use the shared Image component." }],
  },
],

React

| Rule | Summary | | --- | --- | | no-native-html | Ban high-confidence native HTML; suggest UI components by name | | no-react-namespace | Ban import React / import * as React and React.* access | | component-file-name-match | First primary exported component matches kebab file basename | | no-multi-component-files | One module-level primary component per file (*Impl / *Provider / *Context ignored) | | hook-file-name-match | Hook in use-*.ts(x) matches basename | | no-multi-hook-files | One hook per use-*.ts(x) file | | no-jsx-module-constants | No module-level JSX const | | no-jsx-local-constants-in-components | No local JSX const inside components | | no-jsx-variable-reassignment-in-components | No JSX via local reassignment | | no-jsx-iife-in-components | No JSX-returning IIFEs in components | | no-render-helper-functions-in-components | No nested JSX-returning helpers in components |

React JSX rules are scoped to **/*.{jsx,tsx} in the react preset. Hook rules and no-react-namespace also apply to plain .ts (React types / hooks). Most accept { allow?: string[] }.

Limits (v1): class components and forwardRef wrappers are not covered by file-shape / JSX-hygiene rules. Secondary named exports after the first primary component are ignored by component-file-name-match.

no-native-html default ban list:
button · a · input · textarea · select · option · optgroup · label · img · video · audio · picture · source · iframe · dialog · details · summary · progress · ul · ol · li · table · thead · tbody · tfoot · tr · th · td · caption · hr

"dobroslavlabs/no-native-html": ["error", { tags: ["button", "a"] }],

Effect (opt-in — @dobroslavlabs/oxlint/effect)

| Rule | Summary | | --- | --- | | no-run-promise-in-domain | Ban runPromise* outside boundary paths (defaults: /routes/, /runtime/, /cli/, /main.ts, …) | | no-run-promise-in-effect-tests | Ban runPromise* in tests — prefer @effect/vitest it.effect | | no-run-effect-inside-effect | Ban runners inside Effect.gen / Effect.fn | | no-try-catch-in-effect-gen | Ban try/catch inside gen/fn — use Effect.try / catchTag | | prefer-return-yield-star | Prefer return yield* for the terminal yield in a gen/fn body | | no-outdated-effect-api | Ban curated Effect v3 APIs (Effect.catchAll, Context.Tag, …) | | no-effect-run-sync-at-module-scope | Ban top-level runSync / Effect.runSync / *.runSync | | no-singleton-service-export | Ban export const fooService = new FooService() | | require-tagged-error-class | Prefer Schema.TaggedErrorClass over extends Error / Schema.TaggedError | | require-tagged-error-message | Require message on TaggedErrorClass()(tag, schema) schemas | | no-effect-wrapper-helpers | Ban unwrap / fromResult bridges (narrow filenames: from-nullable, effect-result, …) | | no-multiple-effect-provide | Prefer one composed Layer over many Effect.provide in a pipe chain | | prefer-effect-fn | Prefer Effect.fn("Name") over bare module-scope Effect.gen (skips program/main/boundaries) | | no-tagged-error-instanceof | Ban instanceof SomeError for tagged/domain errors (use catchTag) | | no-generic-error-in-fail | Ban new Error(...) in Effect.fail / Result.err (configurable methods) |

Most accept { allow?: string[] }. Pair with @effect/language-service for type-aware checks (floating Effect, full outdated API catalog, etc.).

import effect from "@dobroslavlabs/oxlint/effect";

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

Zod (opt-in — @dobroslavlabs/oxlint/zod)

| Rule | Summary | | --- | --- | | zod-modern-format-validators | Prefer z.email() / z.url() / z.uuid() over z.string().email() style | | zod-schema-naming | Exported z.* schema defs must be PascalCase *Schema |

zod-schema-naming flags definitional z.object() / z.string() etc., not UserSchema.pick() or makeUserSchema().

import zod from "@dobroslavlabs/oxlint/zod";

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

Elysia (opt-in — @dobroslavlabs/oxlint/elysia)

Rules only run in files that import from elysia.

| Rule | Summary | | --- | --- | | no-context-param | Ban typing handler params as Context — destructure fields | | prefer-status-helper | Prefer status(code, value) over set.status in handlers/hooks | | require-route-schema | Require body/query/params/… on post/put/patch (honors .guard() / .group()) | | require-plugin-name | Require { name } on exported new Elysia() plugins (skips .listen / entry/modules paths) | | no-functional-plugin-callback | Prefer new Elysia() over .use((app) => …) | | no-controller-context-class | Ban class methods typed with Context | | prefer-throw-status | Prefer status() / throw status() over throw new Error / string throws | | no-cookie-undefined-check | Check cookie.x.value, not cookie.x as optional | | require-response-schema | When handler uses bare status(), declare a response schema |

import elysia from "@dobroslavlabs/oxlint/elysia";

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

Bun (opt-in — @dobroslavlabs/oxlint/bun)

For Bun apps. Prefer Bun-native APIs over Node fallbacks (docs: Bun.file / Bun.write / Bun.spawn / bun:sqlite). Does not ban node:fs directory APIs (readdir, mkdir, …). Use { allow } for isomorphic packages.

| Rule | Summary | | --- | --- | | prefer-bun-file-read | fs.readFile*Bun.file(…).text() / .json() / .bytes() | | prefer-bun-write | fs.writeFile*Bun.write (not appendFile) | | prefer-bun-spawn | child_process.spawn/fork/execFile*Bun.spawn / Bun.spawnSync | | prefer-import-meta-paths | __dirname / __filenameimport.meta.dir / import.meta.path | | no-node-http-server | Ban http(s).createServer — use Bun.serve or Elysia/Hono | | prefer-bun-sqlite | Ban better-sqlite3 / sqlite3 / node:sqlitebun:sqlite | | prefer-bun-sqlite-strict | Prefer new Database(…, { strict: true }) | | prefer-bun-shell | execa / child_process.exec* shell strings → $`…` | | prefer-response-json | JSON.stringify + end/send/ResponseResponse.json | | no-bun-sleep-sync-in-async | No Bun.sleepSync inside async — use await Bun.sleep |

import bun from "@dobroslavlabs/oxlint/bun";

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

TanStack Router (opt-in — @dobroslavlabs/oxlint/tanstack-router)

Super-strict typed navigation. Rules only run in files that import from @tanstack/react-router, @tanstack/solid-router, or Start re-exports. Prefer string-literal to + params/search, or typed linkOptions (spread / pass-through).

| Rule | Summary | | --- | --- | | no-dynamic-router-to | Ban non-literal to (templates with ${}, concat, variables) on Link / Navigate / navigate / redirect / linkOptions / router.navigate | | no-router-href | Ban href except external URL literals (http(s):, mailto:, tel:, //) | | no-relative-router-to-without-from | Relative to (., .., non-/ paths) requires from | | no-router-type-assertion | Ban casts / annotations / generics that bypass router inference on to/from and hook returns | | require-router-hook-from | Bare useNavigate / useParams / useSearch / … need from or strict: false (Route.useX() OK) | | no-imperative-location-navigation | Ban location / history / router.history for in-app navigation |

import tanstackRouter from "@dobroslavlabs/oxlint/tanstack-router";

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

Develop

bun install
bun run test        # Vitest + Oxlint RuleTester (Node 22+)
bun run typecheck   # strict TypeScript 7
bun run fmt         # oxfmt
bun run lint        # build + ultracite check (dogfoods this package)
bun run build       # tsdown → dist (publint + attw + unused)
bun run check       # build → typecheck → test → fmt:check → lint

Stack: Bun · TypeScript 7 · Ultracite (oxlint + oxfmt) · tsdown · Vitest · @oxlint/plugins

CI (.github/workflows/ci.yml) runs check on main push/PR. It does not publish.

Editor: Oxc VS Code extension (format + fix on save — import sort via oxfmt, unused-import removal via oxlint).

Publish (local only)

bun run login      # npm login --auth-type=web (browser / 2FA)
bun run pack:dry   # check + npm pack --dry-run
bun run release    # npm publish --access public

prepublishOnly runs check; prepack runs build. See CHANGELOG.md for release notes.