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

@neralabs/rerail-pack-react

v0.1.5

Published

Rerail rule pack: eslint-plugin-react and eslint-plugin-react-hooks rules ported to Rerail code rules.

Readme

Rerail rule pack: React

Ports of eslint-plugin-react 7.37.5 and eslint-plugin-react-hooks 7.1.1 rules. A port starts in candidates/rules/ and moves to rules/ and pack.json once it passes the port readiness gates, which CI runs on every port. While pack.json lists no rules, the pack ships none and is never recommended. Every port is scored against the plugins' own findings on the plugins' test cases and the pinned corpus, through the engine's production workspace path. The conformance check (--check, run in CI) scores the test cases only: it gates the ports in rules/ and reports the candidates without gating them. The corpus is scored on demand, with --pack react --corpus excalidraw.

Every rule runs on JavaScript and TypeScript files whose JSX runtime is React or not known; a file whose JSX belongs to another library is skipped. The runtime is the file's @jsxImportSource pragma when it names React, Emotion (@emotion/react) or Theme UI (React) or Preact, Solid, Vue, Stencil, Hono, Qwik, Inferno, Mithril or Hyperapp (another library), or its @jsx pragma when that names React; else an h or createElement imported from Stencil, Preact, Vue, Solid, Hyperapp or Mithril (another library); else its nearest package.json: React when it depends on react, react-dom, react-native or next and on none of vue, @stencil/core, preact, solid-js, @builder.io/qwik, inferno or mithril, another library in the reverse case, unknown otherwise. react-in-jsx-scope also skips files whose @jsx pragma names another factory (Emotion's jsx, for one): the plugin then asks for that factory in scope, which the port does not check.

The pack follows the pack structure and validation contract: it is checked by npx vitest run test/engine/catalog/packs.test.ts -t "pack react".

| Path | What | |---|---| | pack.json | The pack (rerail.rule-pack/v1): its match definition, and no rules until a port passes | | conformance.json | Every port (shipped under rules/, or a candidate under candidates/rules/): its upstream tool and rule, how findings compare and the capabilities it exercises; the pinned tools and the pinned corpus (excalidraw). Written by candidates/build.mjs | | upstream/<tool>/ | The plugin's copied tests (tests/), the cases extracted from them (fixtures/), its recordings (fixtures.expected.json, corpus-excalidraw.expected.json) and the recorder (generate.mjs, sharing upstream/common.mjs and conformance/recorders/eslint-record.mjs); UPSTREAM.md lists the fixtures Rerail wrote beside them (common.mjs AUTHORED): files of other JSX libraries, which the plugins report and the ports skip, and React files whose JSX goes through Emotion, which both report | | divergences.json | Where the ports and the recordings disagree by design: the plugins' findings on the authored files of other JSX libraries | | licenses/<project>/ | The upstream licence and UPSTREAM.md, listing every copied file and extracted case | | candidates/ | Ports still being evaluated, scored but never shipped: the code-rule documents (rules/, written by build.mjs from specs.mjs, except the hand-written react-no-array-index-key.json); probes/ holds the hand-labelled React fact probes |

Re-recording is a maintainer deriving the pack's test data from its pins and archiving it (CONTRIBUTING.md); it is never committed. The recipe (scripts/pack-data/recipes/react.ts) runs each plugin's generate.mjs against the pinned tools (eslint 9.39.5, @typescript-eslint/parser 8.70.1, typescript 5.9.3), the plugins' upstream checkouts and the corpus. The fixtures Rerail wrote (UPSTREAM.md) are authored: a change to them goes in your pull request with git add -f.

npm run fixtures:derive -- --pack react                                     # both plugins
npm run fixtures:derive -- --pack react --tool eslint-plugin-react-hooks    # one
npm run fixtures:push -- --pack react --tool eslint-plugin-react-hooks      # on your own branch: archive it and rewrite its test-data.lock

Rewriting the rule documents and conformance.json after editing candidates/specs.mjs, then scoring one rule with every false positive and false negative printed:

node candidates/build.mjs
node --import tsx conformance/languages/cli.ts --pack react --rule react-jsx-key --fixtures

Rule details

What each rule matches beyond its one-line description: exact matching, edge cases, upstream settings and known divergences.

react-button-has-type

Port of eslint-plugin-react 7.37.5 react/button-has-type with button, submit and reset allowed. Reports a <button> with no type attribute (looked up case-insensitively, as jsx-ast-utils getProp does) or whose first type value is not a literal button/submit/reset. Each leaf of a conditional type is checked, and a non-literal leaf is reported at itself. The same applies to React.createElement('button', props) with the default pragma.

react-hooks-exhaustive-deps

Port of eslint-plugin-react-hooks 7.1.1 react-hooks/exhaustive-deps, missing-dependency report only (no unnecessary/duplicate-dependency reports). Checks the dependency array literal of useEffect, useLayoutEffect, useInsertionEffect, useCallback and useMemo (bare or as React.*) when the inline callback reads a name bound in the calling function (outside the callback) that no dependency's root names. useState/useReducer setters and dispatchers, useRef, useEffectEvent and useTransition results count as stable and need not be listed.

react-hooks-rules-of-hooks

Port of eslint-plugin-react-hooks 7.1.1 react-hooks/rules-of-hooks. A hook call (use, useX, Namespace.useX) is reported at its callee when it runs, in a component or hook (a function named X…/useX, or the callback of memo/forwardRef), conditionally (if/conditional/logical/switch/catch/default branch, or after an earlier return); in a class method or field; in another named function; at the top level; in an anonymous callback inside a component or hook; in a loop; in an async component or hook; and use inside try/catch. ESLint's code-path analysis is approximated syntactically.

react-jsx-key

Port of eslint-plugin-react 7.37.5 react/jsx-key, default options. Reports an element (not a fragment) without key that is an array literal's element, or that a .map(fn) / .from(x, fn) callback returns: the arrow's body, a branch of its conditional body, the right side of its logical body, or a return statement directly in the callback body or in nested if/else branches. Never reported inside React.Children.toArray(...) / Children.toArray(...).

react-jsx-no-comment-textnodes

Port of eslint-plugin-react 7.37.5 react/jsx-no-comment-textnodes: JSX text with a line that starts (after whitespace) with // or /*.

react-jsx-no-duplicate-props

Port of eslint-plugin-react 7.37.5 react/jsx-no-duplicate-props, case-sensitive. Namespaced attribute names and spreads are skipped.

react-jsx-no-target-blank

Port of eslint-plugin-react 7.37.5 react/jsx-no-target-blank with default options (links only, enforceDynamicLinks always, allowReferrer false). Reports an <a> whose last target is possibly _blank (a string, or a conditional with a _blank branch), with an external last href string (scheme: or //) or any href expression, and whose last rel does not give noreferrer on every value it may take (a string, the first quasi of a template, both branches of a conditional, or, when target and rel test the same name, the branch on which target is _blank).

react-jsx-no-undef

Port of eslint-plugin-react 7.37.5 react/jsx-no-undef (allowGlobals: false, module code). Checks a non-DOM JSX tag name, or the root of a member tag name, against file-local bindings; globals, even configured ones, do not count in a module.

react-no-children-prop

Port of eslint-plugin-react 7.37.5 react/no-children-prop (allowFunctions: false): a children JSX attribute, and a createElement call (default pragma) whose second argument is an object literal with a children key.

react-no-danger

Port of eslint-plugin-react 7.37.5 react/no-danger, default options. Only DOM elements (tag name starting lower-case, per jsx-ast-utils elementType) are checked; custom components receiving the prop are not reported.

react-no-danger-with-children

Port of eslint-plugin-react 7.37.5 react/no-danger-with-children. Children means a first child that is not a line break, or a children prop. Props are also read through {...name} spreads of a variable initialised with an object literal. For x.createElement(type, props, ...), props may be an object literal or a variable initialised with one, and children is a third argument or a children prop.

react-no-direct-mutation-state

Port of eslint-plugin-react 7.37.5 react/no-direct-mutation-state. Reports an assignment or update whose target is a member chain rooted at this.state, inside a class component (nearest class extends Component / PureComponent / React.Component / React.PureComponent) or a function that is a property of the object passed to createReactClass. In a constructor it is reported only when inside a call. Reported at this. Function components (the plugin's Components.detect stateless detection) are not modelled.

react-no-find-dom-node

Port of eslint-plugin-react 7.37.5 react/no-find-dom-node: any call whose callee is findDOMNode or a member .findDOMNode.

react-no-is-mounted

Port of eslint-plugin-react 7.37.5 react/no-is-mounted: this.isMounted() inside an object property or a method (ESTree Property / MethodDefinition ancestor).

react-no-render-return-value

Port of eslint-plugin-react 7.37.5 react/no-render-return-value (latest React). The value counts as used when the call's parent (parentheses aside) is a declarator, a property, a return, an arrow body or an assignment.

react-no-string-refs

Port of eslint-plugin-react 7.37.5 react/no-string-refs (latest React, noTemplateLiterals: false): a ref attribute whose value is a string literal, bare or in braces. Template literals are not reported. From React 18.3 on the plugin no longer reports this.refs reads, so neither does the port.

react-no-unescaped-entities

Port of eslint-plugin-react 7.37.5 react/no-unescaped-entities (forbids >, ", ', }). One finding per such character, but only on the first line of a JSX text node (the k-th check holds where that line has at least k of them; ESLint reports each character at its own column). Characters on a text node's later lines are not reported, because a finding is anchored at a node and a text node has no node per line.

react-react-in-jsx-scope

Port of eslint-plugin-react 7.37.5 react/react-in-jsx-scope (pragma React). A JSX opening element or fragment is reported when no React binding is visible: none declared at the top level (import, var/let/const, function), in an enclosing block's own declarations, or as an enclosing function's parameter.

react-self-closing-comp

Port of eslint-plugin-react 7.37.5 react/self-closing-comp (component: true, html: true). Reports an element with a closing tag and no children except whitespace that contains a line break (a same-line space is text and is not reported). Namespaced tags only when lower-case (DOM).

react-void-dom-elements-no-children

Port of eslint-plugin-react 7.37.5 react/void-dom-elements-no-children. Void elements: area, base, br, col, embed, hr, img, input, keygen, link, menuitem, meta, param, source, track, wbr. Reports children, a children attribute or a dangerouslySetInnerHTML attribute (one report each); the same through createElement with an object-literal props argument.