@hyperfrontend/linter§

A TypeScript file, cart.ts, sits on a sheet while a beam reads it line by line; as each line is read its node appears beside the sheet at the same height, nested the way the code nests. Three rules find something: var is underlined and no-var lands beside its node, let count is underlined with prefer-const, and !!item.price with no-extra-boolean-cast. The --fix flag lights on the hf-lint chip and the fixes land one by one: let total, const count and item.price are written in place, each underline retracts, each tag gets a check, and a check lands beside the file's nameA TypeScript file, cart.ts, sits on a sheet while a beam reads it line by line; as each line is read its node appears beside the sheet at the same height, nested the way the code nests. Three rules find something: var is underlined and no-var lands beside its node, let count is underlined with prefer-const, and !!item.price with no-extra-boolean-cast. The --fix flag lights on the hf-lint chip and the fixes land one by one: let total, const count and item.price are written in place, each underline retracts, each tag gets a check, and a check lands beside the file's name

A linter for TypeScript, JavaScript, JSX, JSON and Markdown with its own parsers and no external runtime packages.

What is @hyperfrontend/linter?

@hyperfrontend/linter checks TypeScript, JavaScript, JSX, JSON and Markdown against rules you choose, and fixes what the rules know how to fix. It parses every file with parsers of its own and installs no dependencies.

It is not a drop-in ESLint. It reimplements a selection of rules from ESLint and well-known plugins, under a configuration that reads like ESLint's flat config, and it does not load ESLint plugins, parsers or shareable configs.

Key Features

  • Packaged rules

    Core JavaScript, TypeScript, JSDoc, React, React hooks and package.json rules, and a set of conventions

  • Presets to start from

    The rules the upstream recommended configurations turn on, as plain objects you spread into a block

  • One parse, one traversal

    The listeners of every rule in effect for a file run in a single walk of its tree

  • Rules of your own

    Register them under a prefix with families and test them with testRule

  • Fixes and suggestions

    --fix applies fixes; suggestions, for changes that need your judgement, appear in the JSON report

  • No dependencies

    The package is self-contained; linting loads nothing from npm

Why Use @hyperfrontend/linter?

Fewer packages in the toolchain

A linting setup built on ESLint brings a parser, plugins and their dependencies into every install. This package is one dependency with nothing beneath it, for a project whose checks fit its rules.

Rules you can read and own

Each rule is one module with its specification beside it. When the packaged rules stop short, write and test a rule of your own with the same API they use.

Installation

npm install --save-dev @hyperfrontend/linter

Requires Node.js 24 or later, which loads the TypeScript configuration file without a compiler.

Quick Start

Create lint.config.ts at the project root:

import { CODE, CODE_RULES, on } from '@hyperfrontend/linter'

export default [
  { ignores: ['dist/', 'coverage/'] },
  { files: CODE, rules: CODE_RULES },
  { files: ['src/**/*.ts'], rules: on('no-enum import-order') },
]

Then lint and fix from the project root:

npx hf-lint
npx hf-lint src --fix

Lint a project with @hyperfrontend/linter covers configuration, directives, exit codes, CI and linting from code with lint.

API Overview

EntryWhat it is
@hyperfrontend/linterRunning, configuration types and presets, defineRule and the rule types
/helpersTokens, scopes, JSON properties and positions, for rules of your own
/testingtestRule, which turns a rule's cases into node:test tests
hf-lintThe command line

Every rule, with its options and examples, is in the rule catalogue. Moving from ESLint? Replace ESLint with @hyperfrontend/linter starts with what does and does not carry over.

Limitations

  • No rule uses type information, and every packaged rule reads only the file it lints.
  • No editor integration: run it from the terminal, a hook or CI.
  • No result cache between runs.
  • YAML files are read as plain lines for rules of your own; no packaged rule reads them.

Acknowledgements

The packaged rules reimplement rules from ESLint, typescript-eslint, eslint-plugin-jsdoc, eslint-plugin-react, eslint-plugin-react-hooks and eslint-plugin-package-json, whose messages, options and test cases they follow. Their licences and the details are in NOTICE.md. How the linter came to be written is told in I Replaced ESLint. The First Attempt Worked. I Threw It Away.

Compatibility

Runs on

  • Node.js>=24.0.0supported
  • Browsersnot supported
  • Web Workersnot supported

Needs Node.js 24 or later: configurations are TypeScript modules loaded through Node's own type stripping.

Ships as

  • ESMTree-shakeable
  • CJSNode and older bundlers
  • CLIhf-lint

Architecture Highlights§

Every file is parsed once and every rule's listeners run in one traversal of it; the services rules share, such as scopes and code paths, are computed once per file and never rebuilt. The architecture guide covers the parsers, the shared services and the fix loop.

API Reference§

View:
Organized by entry point

Module Structure

|

3 modules · 99 total exports

Lint from the command line or as a function, configure with ordered blocks in `lint.config.ts`, select the packaged rules and presets, and define rules of your own.

6 fn34 int11 type9 var

What rules ask beyond the tree: tokens and comments around a node, children, scopes and variables, JSON properties, positions, globs, merged fixes, and parsing another file.

24 fn9 int1 type

Specifying a rule: valid texts that must report nothing and invalid texts with the messages, positions and fixed text they must produce, each case one `node:test` test.

1 fn4 int

Browse guides filtered to this packageSuggest a guide