@neralabs/rerail-pack-next
v0.1.4
Published
Rerail rule pack: @next/eslint-plugin-next rules ported to Rerail code rules.
Keywords
Readme
Rerail rule pack: Next.js
21 code rules for Next.js projects, ported from @next/eslint-plugin-next 16.3.8. Each is scored against the
plugin's own findings on the plugin's rule tests, through the engine's production workspace path; no disagreement is
declared today, so the pack has no divergences.json.
The pack follows the pack structure and validation contract: it is checked by
npx vitest run test/engine/catalog/packs.test.ts -t "pack next".
| Path | What |
|---|---|
| pack.json | The pack (rerail.rule-pack/v1): each rule's document, title and group; six rules carry examples |
| rules/ | The code-rule documents (rerail.policy/v1) |
| conformance.json | Each ported rule's upstream rule, how findings compare, and the capabilities it exercises, the shipped rules first and then the candidates; the pinned plugin and the pinned corpora (shadcn-ui, next-examples, commerce) |
| upstream/eslint-plugin-next/ | The plugin's copied rule tests (tests/) and the cases extracted from them (fixtures/), its recordings (fixtures.expected.json, corpus-<name>.expected.json, fixtures.cases.json) and the recorder (generate.mjs). All but the recorder are pack test data, derived from the pins (npm run fixtures:derive) and archived in S3: npm run fixtures:pull |
| candidates/ | Ports that cannot pass their fixtures yet or that fail the port readiness gates (rules/, none today; scored through conformance.json, never gating), the Next fact model's probes (probes/), and the generators that write them and rules/ (build-policies.mjs, build-probes.mjs) |
| licenses/next.js/ | Next.js's licence and UPSTREAM.md, listing every copied file |
The rule documents, conformance.json's and pack.json's rule lists and the candidates are generated, offline:
node packs/next/candidates/build-policies.mjs
node packs/next/candidates/build-probes.mjsRe-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/next.ts) runs upstream/eslint-plugin-next/generate.mjs against the pinned plugin and
corpora (Node 23.6 or later):
npm run fixtures:derive -- --pack next
npm run fixtures:push -- --pack next # on your own branch: archive it and rewrite its test-data.lockScoring one rule, shipped or candidate, with every false positive and false negative printed:
node --import tsx conformance/languages/cli.ts --pack next --rule next-no-img-element --fixturesRule details
What each rule matches beyond its one-line description: exact matching, edge cases, upstream settings and known divergences.
All rules in this chunk are ports of @next/eslint-plugin-next 16.3.8 (rule @next/next/<name>). Note: the rule documents are generated by packs/next/candidates/build-policies.mjs, which prefixes each description with the upstream version and rule code (line ~139); re-running it overwrites the rewritten descriptions unless the generator is updated too.
next-google-font-display
Matches a <link> whose literal href is a Google Fonts CSS URL (https://fonts.googleapis.com/css...) whose query has no display parameter, or has display=auto, block or fallback.
next-google-font-preconnect
Matches a <link> whose literal href starts with https://fonts.gstatic.com and whose rel is not the literal "preconnect".
next-inline-script-id
Matches an element named by the first local name that an import from next/script binds, with children or dangerouslySetInnerHTML and no id. Attributes and the keys of object-literal spreads count; any other spread makes the element uncheckable (no finding).
next-next-script-for-ga
Matches a <script> with a literal src containing the Google Analytics or gtag URL, or whose dangerouslySetInnerHTML object's first property is a template literal whose first quasi contains the GA or GTM script URL.
next-no-assign-module-variable
Matches any variable declaration with a declarator whose identifier is module.
next-no-async-client-component
Only after a top-level "use client" statement. Matches an export default async function with a capitalized name, or the first top-level declaration of the capitalized name that export default exports when it is an async function or a variable initialized with an async arrow.
next-no-before-interactive-script-outside-document
Matches an opening element named by the default import of next/script with a plain strategy="beforeInteractive", unless the path contains /app/ or its segment after the first pages has a name starting with _document.
next-no-css-tags
Matches a <link> with rel="stylesheet" and a string href that does not start with http(s).
next-no-document-import-in-page
Matches an import from next/document unless the part of the path after its last pages is empty or starts with /_document.
next-no-duplicate-head
Flags every <Head> child of a returned element after the first, in a return inside a class extending the default import of next/document.
next-no-head-element
Matches a <head> opening element unless the file's path contains app/.
next-no-head-import-in-document
Matches an import from next/head in a file whose path, between its first and second pages, names a document (name starts with _document, or /_document/index).
next-no-img-element
Matches an <img> opening element with attributes that is not a direct child of <picture>, unless the file is an app-dir metadata image route (path relative to the ESLint cwd matches ^(src/)?app/ and /opengraph-image|twitter-image|icon.<ext>). The violation message is upstream's plus Rerail additions: what <Image /> needs (width and height or fill; a matching images.remotePatterns entry for a remote src) and the eslint-disable comment that keeps <img>.
next-no-location-assign-relative-destination
Matches an assignment to location.href (or window/globalThis/document/self .location.href) or a call of its assign(), whose value's static string prefix is a relative URL.
next-no-page-custom-font
Matches a <link> whose literal href is a Google Fonts CSS URL, unless the file is pages/_document (last pages piece starts with /_document) and the link is inside the default-exported component. Two clauses: outside _document ("only loads for a single page"), and inside _document but outside the default-exported component ("outside <Head> disables font optimization").
next-no-script-component-in-head
Matches a <Head> element with a direct <Script> element child, in a file that imports next/head.
next-no-styled-jsx-in-document
Matches a <style> opening element with a jsx attribute in a file whose path, between its first and second pages, names a document.
next-no-sync-scripts
Matches a <script> opening element with a src attribute and neither async nor defer.
next-no-title-in-document-head
Matches the first <title> element child of a <Head> element, in a file with an import from next/document that binds the local name Head.
next-no-typos
Matches an exported function or variable whose name is one edit away from getStaticProps, getStaticPaths or getServerSideProps, in a file whose segment after the first pages is non-empty and not under /api.
next-no-unwanted-polyfillio
Matches a <script> (or the first local name an import from next/script binds) with a plain string src on a polyfill.io host whose first features parameter lists a feature Next.js already polyfills.
