# Rule catalogue

Every rule `@hyperfrontend/linter` ships, by family. A rule runs once a configuration block turns it on by its id, and a preset turns on every rule marked with it. Each rule's heading is a stable link target, so `#typescriptno-namespace` always finds `typescript/no-namespace`.

| Family | Rules | Fixable | Preset |
| ------ | ----: | ------: | ------ |
| [Core rules](#core-rules) | 48 | 5 | [`CODE_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-CODE_RULES) |
| [TypeScript rules](#typescript-rules) | 26 | 9 | [`CODE_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-CODE_RULES) |
| [JSDoc rules](#jsdoc-rules) | 32 | 8 | [`JSDOC_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-JSDOC_RULES) |
| [React rules](#react-rules) | 19 | 2 | [`REACT_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-REACT_RULES) |
| [React hooks rules](#react-hooks-rules) | 2 | 0 | [`REACT_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-REACT_RULES) |
| [package.json rules](#packagejson-rules) | 1 | 0 |  |
| [Convention rules](#convention-rules) | 28 | 11 |  |

🔧 marks a rule whose fixes `--fix` applies. Suggestions, for changes that need judgement, appear in the JSON report and are described under the rules that offer them.

## Core rules

Reimplemented from [ESLint](https://eslint.org/docs/latest/rules/)'s own rules. [`CODE_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-CODE_RULES) turns on the ones `eslint:recommended` does.

| Rule | Reads | 🔧 | `CODE_RULES` |
| ---- | ----- | :-: | :-: |
| [`for-direction`](#for-direction) | TypeScript, JavaScript |  | ✅ |
| [`no-async-promise-executor`](#no-async-promise-executor) | TypeScript, JavaScript |  | ✅ |
| [`no-case-declarations`](#no-case-declarations) | TypeScript, JavaScript |  | ✅ |
| [`no-compare-neg-zero`](#no-compare-neg-zero) | TypeScript, JavaScript |  | ✅ |
| [`no-cond-assign`](#no-cond-assign) | TypeScript, JavaScript |  | ✅ |
| [`no-constant-binary-expression`](#no-constant-binary-expression) | TypeScript, JavaScript |  | ✅ |
| [`no-constant-condition`](#no-constant-condition) | TypeScript, JavaScript |  | ✅ |
| [`no-control-regex`](#no-control-regex) | TypeScript, JavaScript |  | ✅ |
| [`no-debugger`](#no-debugger) | TypeScript, JavaScript |  | ✅ |
| [`no-delete-var`](#no-delete-var) | TypeScript, JavaScript |  | ✅ |
| [`no-dupe-else-if`](#no-dupe-else-if) | TypeScript, JavaScript |  | ✅ |
| [`no-duplicate-case`](#no-duplicate-case) | TypeScript, JavaScript |  | ✅ |
| [`no-empty`](#no-empty) | TypeScript, JavaScript |  | ✅ |
| [`no-empty-character-class`](#no-empty-character-class) | TypeScript, JavaScript |  | ✅ |
| [`no-empty-pattern`](#no-empty-pattern) | TypeScript, JavaScript |  | ✅ |
| [`no-empty-static-block`](#no-empty-static-block) | TypeScript, JavaScript |  | ✅ |
| [`no-ex-assign`](#no-ex-assign) | TypeScript, JavaScript |  | ✅ |
| [`no-extra-boolean-cast`](#no-extra-boolean-cast) | TypeScript, JavaScript | 🔧 | ✅ |
| [`no-fallthrough`](#no-fallthrough) | TypeScript, JavaScript |  | ✅ |
| [`no-global-assign`](#no-global-assign) | TypeScript, JavaScript |  | ✅ |
| [`no-invalid-regexp`](#no-invalid-regexp) | TypeScript, JavaScript |  | ✅ |
| [`no-irregular-whitespace`](#no-irregular-whitespace) | TypeScript, JavaScript |  | ✅ |
| [`no-loss-of-precision`](#no-loss-of-precision) | TypeScript, JavaScript |  | ✅ |
| [`no-misleading-character-class`](#no-misleading-character-class) | TypeScript, JavaScript |  | ✅ |
| [`no-nonoctal-decimal-escape`](#no-nonoctal-decimal-escape) | TypeScript, JavaScript |  | ✅ |
| [`no-octal`](#no-octal) | TypeScript, JavaScript |  | ✅ |
| [`no-prototype-builtins`](#no-prototype-builtins) | TypeScript, JavaScript |  | ✅ |
| [`no-regex-spaces`](#no-regex-spaces) | TypeScript, JavaScript | 🔧 | ✅ |
| [`no-restricted-imports`](#no-restricted-imports) | TypeScript, JavaScript |  |  |
| [`no-self-assign`](#no-self-assign) | TypeScript, JavaScript |  | ✅ |
| [`no-shadow-restricted-names`](#no-shadow-restricted-names) | TypeScript, JavaScript |  | ✅ |
| [`no-sparse-arrays`](#no-sparse-arrays) | TypeScript, JavaScript |  | ✅ |
| [`no-unexpected-multiline`](#no-unexpected-multiline) | TypeScript, JavaScript |  | ✅ |
| [`no-unsafe-finally`](#no-unsafe-finally) | TypeScript, JavaScript |  | ✅ |
| [`no-unsafe-optional-chaining`](#no-unsafe-optional-chaining) | TypeScript, JavaScript |  | ✅ |
| [`no-unused-labels`](#no-unused-labels) | TypeScript, JavaScript | 🔧 | ✅ |
| [`no-unused-private-class-members`](#no-unused-private-class-members) | TypeScript, JavaScript |  | ✅ |
| [`no-useless-assignment`](#no-useless-assignment) | TypeScript, JavaScript |  |  |
| [`no-useless-backreference`](#no-useless-backreference) | TypeScript, JavaScript |  | ✅ |
| [`no-useless-catch`](#no-useless-catch) | TypeScript, JavaScript |  | ✅ |
| [`no-useless-escape`](#no-useless-escape) | TypeScript, JavaScript |  | ✅ |
| [`no-var`](#no-var) | TypeScript, JavaScript | 🔧 | ✅ |
| [`prefer-const`](#prefer-const) | TypeScript, JavaScript | 🔧 | ✅ |
| [`prefer-rest-params`](#prefer-rest-params) | TypeScript, JavaScript |  | ✅ |
| [`prefer-spread`](#prefer-spread) | TypeScript, JavaScript |  | ✅ |
| [`require-yield`](#require-yield) | TypeScript, JavaScript |  | ✅ |
| [`use-isnan`](#use-isnan) | TypeScript, JavaScript |  | ✅ |
| [`valid-typeof`](#valid-typeof) | TypeScript, JavaScript |  | ✅ |

---

### `for-direction`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid a `for` loop whose update moves the counter away from the bound its test checks.

#### Rule Details

A loop such as `for (let i = 0; i < 10; i--)` never ends by its test, which is almost always a typo in the update. The rule reports a `for` loop whose test compares a counter with `<`, `<=`, `>` or `>=` and whose update moves that counter the wrong way: `i++` or `i--`, or `i += n` and `i -= n` where the step is known without running the code (a literal, arithmetic on literals, or a variable assigned once with such a value). An unknown or zero step is not reported. The rule does not fix.

Reimplements [ESLint's `for-direction`](https://eslint.org/docs/latest/rules/for-direction).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
for (let i = 0; i < 10; i--) {}

for (let i = 10; i >= 0; i++) {}

const step = -1
for (let i = 0; i < 10; i += step) {}
```

##### ✅ Correct

```ts
for (let i = 0; i < 10; i++) {}

for (let i = 10; i >= 0; i -= 2) {}

for (let i = 0; i < 10; i += step()) {}
```

---

### `no-async-promise-executor`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid an async function as the executor of `new Promise(...)`.

#### Rule Details

An error thrown inside an async executor rejects the executor's own promise, not the one being constructed, so it is lost and the new promise never settles. An async executor also usually means the code awaits something it could have returned directly. The rule reports the `async` keyword of a function or arrow passed as the first argument to `new Promise(...)`. The rule does not fix.

Reimplements [ESLint's `no-async-promise-executor`](https://eslint.org/docs/latest/rules/no-async-promise-executor).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const result = new Promise(async (resolve) => {
  resolve(await load())
})
```

##### ✅ Correct

```ts
const result = new Promise((resolve, reject) => {
  load().then(resolve, reject)
})

const direct = load()
```

---

### `no-case-declarations`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid `let`, `const`, function and class declarations directly under a `case` or `default` clause.

#### Rule Details

A declaration directly under a case clause belongs to the whole `switch` block, so every clause can see it, but it is only initialised when its own clause runs. Reaching it from another clause throws, or, for a function, quietly works only after hoisting. Wrapping the clause body in braces gives the declaration a block of its own. The rule reports every `let`, `const`, [`using`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using), function and class declaration that is a direct statement of a clause; `var` is left alone. The rule does not fix.

Reimplements [ESLint's `no-case-declarations`](https://eslint.org/docs/latest/rules/no-case-declarations).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
switch (kind) {
  case 'a':
    const label = 'first'
    break
  default:
    function fallback() {}
}
```

##### ✅ Correct

```ts
switch (kind) {
  case 'a': {
    const label = 'first'
    break
  }
  default: {
    function fallback() {}
  }
}
```

#### Limitations

The original offers a suggestion that wraps the clause body in braces; this rule reports without one.

---

### `no-compare-neg-zero`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid comparing a value against `-0` with a comparison operator.

#### Rule Details

Every equality and relational operator treats `-0` and `0` as the same value, so `x === -0` is also true for `0` and never tells them apart. The rule reports a comparison (`==`, `===`, `!=`, `!==`, `<`, `<=`, `>`, `>=`) with `-0` written as either operand. To test for negative zero, use `Object.is(x, -0)`. The rule does not fix.

Reimplements [ESLint's `no-compare-neg-zero`](https://eslint.org/docs/latest/rules/no-compare-neg-zero).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
if (x === -0) {
  reset()
}
```

##### ✅ Correct

```ts
if (Object.is(x, -0)) {
  reset()
}

if (x === 0) {
  reset()
}
```

---

### `no-cond-assign`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid an assignment as the test of a condition unless it is wrapped in its own parentheses.

#### Rule Details

`if (user = find(id))` is usually a mistyped comparison. When the assignment is meant, wrapping it in a second pair of parentheses says so. The rule reports an assignment that is the whole test of an `if`, `while`, `do...while`, `for` or conditional (`?:`) expression and is not parenthesised on its own: two pairs for an `if`, a loop or a ternary, one pair for a `for` loop, whose head parentheses do not count. The rule does not fix.

Reimplements [ESLint's `no-cond-assign`](https://eslint.org/docs/latest/rules/no-cond-assign), in its default `"except-parens"` mode.

#### Options

This rule has no options. The original's string option is not read, so its `"always"` mode, which reports every assignment in a test even when parenthesised, is not available.

#### Examples

##### ❌ Incorrect

```ts
if (user = find(id)) {
  greet(user)
}

while (node = node.next) {}
```

##### ✅ Correct

```ts
if ((user = find(id))) {
  greet(user)
}

if (user === find(id)) {
  greet(user)
}
```

#### Limitations

Only an assignment that is the whole test is checked, as in the original's default mode: one nested inside it, as in `if (ready && (value = read()))`, is not reported.

---

### `no-constant-binary-expression`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid comparisons and logical expressions whose outcome does not depend on the value being tested.

#### Rule Details

Some expressions look like they test a value but always evaluate the same way, usually because of operator precedence or a misunderstanding of how `??` and `===` work. The rule reports:

- a `&&` or `||` whose left side is always truthy or always falsy, and a `??` whose left side is never or always nullish, such as `{ ...options } ?? fallback`;
- an `==`, `===`, `!=` or `!==` against `null`, `undefined` or a boolean whose result is fixed by the other operand's shape alone, such as `a + b === null` or `!value == null`;
- a strict comparison against an object, array, function or class created on the spot, which can never be equal to anything else, and a loose comparison of two such values.

Names bound to the global `undefined`, `Boolean` and the like are only treated as constant when they are not shadowed. The rule does not fix.

Reimplements [ESLint's `no-constant-binary-expression`](https://eslint.org/docs/latest/rules/no-constant-binary-expression).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const value1 = +x == null
const value2 = { ...options } ?? fallback
const value3 = items === []
const value4 = !foo == null
```

##### ✅ Correct

```ts
const value1 = x == null
const value2 = options ?? fallback
const value3 = items.length === 0
const value4 = foo == null
```

---

### `no-constant-condition`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid conditions that always hold or never do.

#### Rule Details

A test that cannot change, such as `if (true)` or `while (1)`, is usually a leftover of debugging or a mistake that makes a branch dead. The rule reports a constant test of an `if`, a conditional (`?:`) expression, and a `while`, `do...while` or `for` loop. Constant means the value is known from the code alone: literals, object and function expressions, `typeof` results, and the like.

Two loop forms pass: `while (true)`, the idiom for a loop that ends by `break`, and any constant loop that a `yield` inside it can suspend, since the consumer of the generator decides when it ends. A `for (;;)` loop has no test and is not reported. The rule does not fix.

Reimplements [ESLint's `no-constant-condition`](https://eslint.org/docs/latest/rules/no-constant-condition), in its default mode.

#### Options

This rule has no options. The original's [`checkLoops`](https://eslint.org/docs/latest/rules/no-constant-condition#options) option is not read: every loop except `while (true)` is checked, the original's default.

#### Examples

##### ❌ Incorrect

```ts
if (false) {
  debug()
}

while (1) {
  poll()
}

const label = typeof value ? 'set' : 'unset'
```

##### ✅ Correct

```ts
if (ready) {
  run()
}

while (true) {
  if (poll()) break
}

function* ids() {
  for (let id = 0; true; id++) yield id
}
```

---

### `no-control-regex`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid control characters (U+0000 to U+001F) in regular expressions.

#### Rule Details

Control characters are rarely what a pattern means to match, and a `\x1f` in a pattern is more often a typo or a copied byte than a deliberate test. The rule reports a regular expression literal, or a `RegExp(...)` or `new RegExp(...)` call with a string pattern, that holds a control character written as a `\x` or `\u` escape or as the raw character itself. The readable escapes such as `\t` and `\n` are left alone, and so are control escapes of the form `\cX`. The message lists the characters found. The rule does not fix.

`RegExp` is recognised when it names the global, is reached through `globalThis`, `window`, [`self`](https://developer.mozilla.org/en-US/docs/Web/API/Window/self) or `global`, or is held in a constant.

Reimplements [ESLint's `no-control-regex`](https://eslint.org/docs/latest/rules/no-control-regex).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const unitSeparator = /\x1f/
const nul = new RegExp('\\x00')
```

##### ✅ Correct

```ts
const space = /\x20/
const tab = /\t/
const lineFeed = new RegExp('\\cJ')
```

---

### `no-debugger`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid [`debugger`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger) statements.

#### Rule Details

A [`debugger`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger) statement pauses execution whenever developer tools are open, which is useful while debugging and wrong in committed code. The rule reports every [`debugger`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger) statement. It does not fix: removing a statement belongs to the author, and a breakpoint in the editor does the same job without a change to the source.

Reimplements [ESLint's `no-debugger`](https://eslint.org/docs/latest/rules/no-debugger).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
function total(items: number[]): number {
  debugger
  return items.reduce((sum, item) => sum + item, 0)
}
```

##### ✅ Correct

```ts
function total(items: number[]): number {
  return items.reduce((sum, item) => sum + item, 0)
}
```

---

### `no-delete-var`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid the `delete` operator on a variable.

#### Rule Details

`delete` removes properties from objects. Applied to a plain variable name it does nothing in sloppy-mode code and returns `false`, and in strict code, which includes every module, it is a syntax error. The rule reports a `delete` whose operand is a bare identifier. To clear a variable, assign `undefined` to it. The rule does not fix.

Reimplements [ESLint's `no-delete-var`](https://eslint.org/docs/latest/rules/no-delete-var).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
var cache = {}
delete cache
```

##### ✅ Correct

```ts
const cache: Record<string, number> = { hits: 1 }
delete cache.hits
```

---

### `no-dupe-else-if`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid an `else if` branch whose condition repeats, or is covered by, an earlier condition of the same chain.

#### Rule Details

In an `if`/`else if` chain only the first matching branch runs, so a later branch whose condition an earlier one already decides can never run. That is almost always a copy-and-paste slip where a different condition was meant. The rule compares each branch's condition with the conditions before it, token by token, and understands `||` and `&&`: a branch is reported when every way its condition can hold is already caught above, so `a && b` after `a` is reported, and `a || b` after `a` and then `b` is reported. Operands are compared as written, without evaluating them. The rule does not fix.

Reimplements [ESLint's `no-dupe-else-if`](https://eslint.org/docs/latest/rules/no-dupe-else-if).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
if (isAdmin) {
  grant()
} else if (isEditor) {
  review()
} else if (isAdmin) {
  audit()
}

if (a) {
  first()
} else if (a && b) {
  second()
}
```

##### ✅ Correct

```ts
if (isAdmin) {
  grant()
} else if (isEditor) {
  review()
} else if (isViewer) {
  audit()
}

if (a && b) {
  first()
} else if (a) {
  second()
}
```

---

### `no-duplicate-case`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid two `case` labels in one `switch` that are written the same way.

#### Rule Details

A `switch` runs the first clause whose label matches, so a second clause with the same label can never be reached, which usually means a label was copied and not changed. The rule reports every clause whose label repeats an earlier label of the same `switch`, compared token by token, so `case a.b:` and `case a . b:` count as the same and `case 1:` and `case 1.0:` do not. The rule does not fix.

Reimplements [ESLint's `no-duplicate-case`](https://eslint.org/docs/latest/rules/no-duplicate-case).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
switch (kind) {
  case 'file':
    open()
    break
  case 'folder':
    expand()
    break
  case 'file':
    preview()
    break
}
```

##### ✅ Correct

```ts
switch (kind) {
  case 'file':
    open()
    break
  case 'folder':
    expand()
    break
  case 'link':
    follow()
    break
}
```

---

### `no-empty`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid empty block statements and empty `switch` statements.

#### Rule Details

An empty block is usually unfinished code, or an error silently swallowed by an empty `catch`. The rule reports a block statement with no statements, such as the body of an `if`, a loop, a `try` or a `catch`, and a `switch` with no cases. A comment inside the braces says the emptiness is intended and the block is left alone. Function bodies are never reported. The rule does not fix.

Reimplements [ESLint's `no-empty`](https://eslint.org/docs/latest/rules/no-empty).

#### Options

| Option                        | Type      | Default | Meaning                                |
| ----------------------------- | --------- | ------- | -------------------------------------- |
| [`allowEmptyCatch`](#no-empty) | `boolean` | `false` | Whether an empty `catch` block passes. |

#### Examples

##### ❌ Incorrect

```ts
if (ready) {
}

try {
  run()
} catch (error) {}

switch (kind) {
}
```

##### ✅ Correct

```ts
if (ready) {
  // nothing to do until the next tick
}

try {
  run()
} catch (error) {
  report(error)
}

function noop(): void {}
```

##### ✅ Correct, with { "allowEmptyCatch": true }

```ts
try {
  run()
} catch {}
```

#### Limitations

The original offers a suggestion that adds an "empty" comment to the block; this rule reports without one.

---

### `no-empty-character-class`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid empty character classes (`[]`) in regular expression literals.

#### Rule Details

An empty character class matches no character at all, so the whole expression around it can never match. It is usually a class whose contents were lost, or an attempt at "any character", which is written `[^]`. The rule reports a regular expression literal holding an empty, non-negated class anywhere in its pattern, nested classes of the `v` flag included. The negated empty class `[^]` is left alone. The rule does not fix.

Reimplements [ESLint's `no-empty-character-class`](https://eslint.org/docs/latest/rules/no-empty-character-class).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const never = /^abc[]/
const nested = /[a[]]/v
```

##### ✅ Correct

```ts
const letters = /^abc[a-z]/
const anything = /^abc[^]/
const bracket = /\[]/
```

#### Limitations

Patterns passed to `RegExp(...)` as strings are not read, as in the original.

---

### `no-empty-pattern`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid empty destructuring patterns.

#### Rule Details

A pattern such as `const {} = options` or `const { a: {} } = options` binds no name at all. It is usually a typo for a default value, `{ a = {} }`. The rule reports every empty object pattern and empty array pattern, in declarations, assignments and parameters alike. The rule does not fix.

Reimplements [ESLint's `no-empty-pattern`](https://eslint.org/docs/latest/rules/no-empty-pattern).

#### Options

This rule has no options. The original's [`allowObjectPatternsAsParameters`](https://eslint.org/docs/latest/rules/no-empty-pattern#options) option is not read, so an empty object pattern as a parameter is always reported.

#### Examples

##### ❌ Incorrect

```ts
const {} = options
const [] = items
const {
  settings: {},
} = options

function start({}) {}
```

##### ✅ Correct

```ts
const { settings = {} } = options
const [first] = items

function start({ port }: { port: number }) {}
```

---

### `no-empty-static-block`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid empty class static blocks, `static {}`.

#### Rule Details

A class `static { }` block with nothing in it does nothing, and is usually left over from removed initialisation code or an unfinished change. The rule reports a static block with no statements. A comment inside the braces says the emptiness is intended, and the block is then left alone. The rule does not fix.

Reimplements [ESLint's `no-empty-static-block`](https://eslint.org/docs/latest/rules/no-empty-static-block).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
class Registry {
  static {}
}
```

##### ✅ Correct

```ts
class Registry {
  static entries: string[] = []
  static {
    Registry.entries.push('default')
  }
}

class Placeholder {
  static {
    // intentionally empty
  }
}
```

---

### `no-ex-assign`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid assigning to the parameter of a `catch` clause.

#### Rule Details

The `catch` parameter holds the exception that was thrown. Assigning to it replaces that exception, so whatever handles or rethrows it afterwards works with something else, and the original error is lost. The rule reports every write to a binding declared by a `catch` parameter, destructured ones included. To transform the error, store the result in a new variable. The rule does not fix.

Reimplements [ESLint's `no-ex-assign`](https://eslint.org/docs/latest/rules/no-ex-assign).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
try {
  run()
} catch (error) {
  error = new Error('run failed')
  throw error
}
```

##### ✅ Correct

```ts
try {
  run()
} catch (error) {
  throw new Error('run failed', { cause: error })
}
```

---

### `no-extra-boolean-cast`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid `!!value` and `Boolean(value)` where the value is already read as a boolean.

#### Rule Details

The test of an `if`, a loop or a conditional expression, the operand of `!` and the argument of `Boolean()` all convert their value to a boolean already, so a cast there adds nothing but noise. The rule reports a double negation (`!!value`) or a `Boolean(...)` call, with or without `new`, in one of those places.

The fix removes the cast and keeps the parentheses the bare value then needs: `if (!!a)` becomes `if (a)`, `!Boolean(a && b)` becomes `!(a && b)`, `Boolean()` becomes `false`. It is withheld when a comment inside the cast would be lost, or when the call spreads its argument or takes more than one.

Reimplements [ESLint's `no-extra-boolean-cast`](https://eslint.org/docs/latest/rules/no-extra-boolean-cast).

#### Options

This rule has no options. The original's [`enforceForInnerExpressions`](https://eslint.org/docs/latest/rules/no-extra-boolean-cast#options) and [`enforceForLogicalOperands`](https://eslint.org/docs/latest/rules/no-extra-boolean-cast#options) options are not read, so a cast that is an operand of `&&`, `||` or `??` inside a test is not reported.

#### Examples

##### ❌ Incorrect

```ts
if (!!user) {
  greet(user)
}

const missing = !Boolean(user)

while (Boolean(queue.length)) {
  queue.pop()
}
```

##### ✅ Correct

```ts
if (user) {
  greet(user)
}

const present = !!user
const flag = Boolean(user)
```

---

### `no-fallthrough`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid a `switch` case from falling through into the next one without a comment saying so.

#### Rule Details

When the end of a case can be reached, control runs on into the next case. That is sometimes intended and far more often a forgotten `break`. The rule follows the code paths of each case and reports the next case when the end of the previous one is reachable: no `break`, `return`, `throw` or `continue` stops every path.

A comment says the fall-through is meant when it contains "falls through", "fall through" or "fallthrough", in any letter case, and is the last comment before the next case, or the last one inside a block that is the case's only statement. Linter directive comments do not count. An empty case directly above the next one, as in `case 'a': case 'b':`, is a shared label and passes; one separated from the next case by a line is reported. The rule does not fix.

Reimplements [ESLint's `no-fallthrough`](https://eslint.org/docs/latest/rules/no-fallthrough).

#### Options

This rule has no options. The original's options [`commentPattern`](https://eslint.org/docs/latest/rules/no-fallthrough#options), [`allowEmptyCase`](https://eslint.org/docs/latest/rules/no-fallthrough#options) and [`reportUnusedFallthroughComment`](https://eslint.org/docs/latest/rules/no-fallthrough#options) are not read.

#### Examples

##### ❌ Incorrect

```ts
switch (kind) {
  case 'warn':
    log(kind)
  case 'error':
    alert(kind)
}
```

##### ✅ Correct

```ts
switch (kind) {
  case 'warn':
    log(kind)
    break
  case 'error':
    alert(kind)
}

switch (kind) {
  case 'info':
  case 'warn':
    log(kind)
  // falls through
  case 'error':
    alert(kind)
}
```

---

### `no-global-assign`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid assigning to read-only globals such as `Object`, `undefined` or `window`.

#### Rule Details

Overwriting a built-in global breaks every other piece of code that relies on it, and in strict code assigning to one such as `undefined` throws. The rule reports every write, an assignment, an update such as `++` or a destructuring target, to a global variable that is read-only: the language's built-ins, and the globals the configuration declares as read-only through its language settings. A local variable that shadows the global is not reported. The rule does not fix.

Reimplements [ESLint's `no-global-assign`](https://eslint.org/docs/latest/rules/no-global-assign).

#### Options

| Option                   | Type       | Default | Meaning                                                       |
| ------------------------ | ---------- | ------- | ------------------------------------------------------------- |
| [`exceptions`](#no-global-assign) | `string[]` | `[]`    | Names of read-only globals that may be assigned all the same. |

#### Examples

##### ❌ Incorrect

```ts
Object = null
undefined = 1
```

##### ✅ Correct

```ts
let Object = null
const value = undefined
```

##### ✅ Correct, with { "exceptions": ["Object"] }

```ts
Object = null
```

---

### `no-invalid-regexp`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid `RegExp(...)` calls with a pattern or flags the engine refuses.

#### Rule Details

A regular expression literal with a syntax error fails to parse, so the problem shows up at once. A pattern passed to `RegExp` as a string is only checked when the call runs, where it throws. The rule reads `RegExp(...)` and `new RegExp(...)` calls whose arguments are string literals and reports:

- flags the language does not know, a flag given twice, or `u` and `v` together;
- a pattern the engine refuses under the flags given, with the engine's reason in the message.

When the flags are not a string literal, the pattern is reported only if no choice of flags would accept it. `RegExp` is recognised when it names the global, is reached through the global object, or is held in a constant. The rule does not fix.

Reimplements [ESLint's `no-invalid-regexp`](https://eslint.org/docs/latest/rules/no-invalid-regexp).

#### Options

This rule has no options. The original's [`allowConstructorFlags`](https://eslint.org/docs/latest/rules/no-invalid-regexp#options) option is not read, so a flag the language does not know is always reported.

#### Examples

##### ❌ Incorrect

```ts
const unclosed = new RegExp('[')
const unknownFlag = RegExp('.', 'z')
const both = new RegExp('a', 'uv')
```

##### ✅ Correct

```ts
const word = new RegExp('\\w+', 'g')
const dynamic = new RegExp(pattern, flags)
```

---

### `no-irregular-whitespace`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid whitespace other than spaces, tabs and line breaks outside string literals.

#### Rule Details

A no-break space, a zero-width space or a byte-order mark in the middle of a file looks like an ordinary space, or like nothing, in most editors, yet the engine does not always treat it as whitespace, and it can break a token or a diff in ways that are hard to see. Such characters usually arrive by copy and paste. The rule reports every run of them: form feed and vertical tab, U+0085, U+00A0, U+1680, U+180E, U+2000 to U+200B, U+2028, U+2029, U+202F, U+205F, U+3000 and U+FEFF. String literals may hold them on purpose and are skipped unless [`skipStrings`](#no-irregular-whitespace) is false. Comments, template literals and regular expressions are always read. The rule does not fix.

Reimplements [ESLint's `no-irregular-whitespace`](https://eslint.org/docs/latest/rules/no-irregular-whitespace).

#### Options

| Option                    | Type      | Default | Meaning                                                     |
| ------------------------- | --------- | ------- | ----------------------------------------------------------- |
| [`skipStrings`](#no-irregular-whitespace) | `boolean` | `true`  | Whether irregular whitespace inside string literals passes. |

The original's [`skipComments`](https://eslint.org/docs/latest/rules/no-irregular-whitespace#options), [`skipRegExps`](https://eslint.org/docs/latest/rules/no-irregular-whitespace#options), [`skipTemplates`](https://eslint.org/docs/latest/rules/no-irregular-whitespace#options) and [`skipJSXText`](https://eslint.org/docs/latest/rules/no-irregular-whitespace#options) options are not read; those places are always checked, the original's default.

#### Examples

The examples hold invisible characters: a zero-width space (U+200B) in the comment and a no-break space (U+00A0) in the strings.

##### ❌ Incorrect

```ts
// the​ running total
const total = 1
```

##### ❌ Incorrect, with { "skipStrings": false }

```ts
const label = 'a b'
```

##### ✅ Correct

```ts
const total = 1
const label = 'a b'
```

---

### `no-loss-of-precision`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid number literals that a double-precision float cannot hold exactly as written.

#### Rule Details

JavaScript numbers are 64-bit floats with about 15 to 17 significant decimal digits. A literal with more precision than that, such as `9007199254740993`, is silently stored as a nearby number, so the value the code uses is not the one the author wrote. The rule reports a number literal, in decimal, binary, octal or hexadecimal notation and with or without numeric separators, whose stored value no longer prints as the digits written. Trailing zeros and exponent notation that round-trip exactly pass. BigInt literals are never reported. The rule does not fix.

Reimplements [ESLint's `no-loss-of-precision`](https://eslint.org/docs/latest/rules/no-loss-of-precision).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const big = 9007199254740993
const long = 5123000000000000000000000000001
const precise = 1.230000000000000000000000000001
const hex = 0x20000000000001
```

##### ✅ Correct

```ts
const big = 9007199254740991
const exact = 12345
const scaled = 1.23e30
const huge = 9007199254740993n
```

---

### `no-misleading-character-class`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid character classes holding characters that are written as one but made of several code points.

#### Rule Details

A character class matches one character at a time, so a symbol that is really a sequence does not match as written: the class matches each of its parts on their own. The rule reports a class in a regular expression literal, or in the string pattern of a `RegExp(...)` call, that holds:

- a surrogate pair, such as an emoji, without the `u` or `v` flag;
- a character followed by a combining mark, such as `A` with a combining accent;
- an emoji followed by a skin-tone modifier;
- a flag written as two regional indicator symbols;
- a sequence joined with zero-width joiners, such as a family emoji.

Characters written as escapes are read the same as the characters themselves, and each problem is reported where it stands in the source. The rule does not fix.

Reimplements [ESLint's `no-misleading-character-class`](https://eslint.org/docs/latest/rules/no-misleading-character-class).

#### Options

This rule has no options. The original's [`allowEscape`](https://eslint.org/docs/latest/rules/no-misleading-character-class#options) option is not read, so escaped sequences are always reported.

#### Examples

##### ❌ Incorrect

```ts
const thumb = /^[👍]$/
const toned = /^[👍🏻]$/u
const flag = /^[🇯🇵]$/u
```

##### ✅ Correct

```ts
const thumb = /^[👍]$/u
const either = /^(?:👍🏻|👎)$/u
```

#### Limitations

The original offers a suggestion that adds the `u` flag to a pattern whose only problem is a surrogate pair; this rule reports without one.

---

### `no-nonoctal-decimal-escape`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid the escapes `\8` and `\9` in string literals.

#### Rule Details

`\8` and `\9` look like octal escapes but escape nothing: in sloppy-mode code they stand for the digits `8` and `9`, and in strict code they are a syntax error. They are usually a typo for an octal or a `\x` escape, or a backslash that was meant to be doubled. The rule reports each `\8` and `\9` in a string literal, skipping a backslash that is itself escaped (`'\\8'`).

This linter's parser refuses `\8` and `\9` in JavaScript and TypeScript string literals, so such code is reported as a parsing error before any rule runs. The rule reports in the one place the parser lets them through: the quoted value of a JSX attribute, where backslashes are not escapes and the text is taken as written. The rule does not fix.

Reimplements [ESLint's `no-nonoctal-decimal-escape`](https://eslint.org/docs/latest/rules/no-nonoctal-decimal-escape).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
const label = <input pattern="\8" />
```

##### ✅ Correct

```ts
const digit = '8'
const escaped = '\\8'
```

#### Limitations

The original offers suggestions that rewrite the escape as the digit or as a `\u` escape; this rule reports without them.

---

### `no-octal`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid legacy octal number literals such as `071`.

#### Rule Details

A number written with a leading zero, such as `071`, is read as octal in sloppy-mode code, so it stands for 57 while most readers see seventy-one, and `08` silently falls back to decimal. In strict code, which includes every module and class body, such literals are a syntax error. Write `0o71` for an octal value or drop the leading zero for a decimal one.

This linter's parser refuses legacy octal literals in every file, scripts included, so code that holds one fails to parse and is reported as a parsing error before any rule runs. The rule therefore never reports by itself; it exists so that a configuration ported from ESLint keeps the same rule id and the same intent.

Reimplements [ESLint's `no-octal`](https://eslint.org/docs/latest/rules/no-octal).

#### Options

This rule has no options.

#### Examples

A legacy octal literal such as `0755` fails to parse before any rule runs, so the file is reported as a parsing error rather than by this rule.

##### ✅ Correct

```ts
const permissions = 0o755
const count = 71
```

---

### `no-prototype-builtins`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid calling [`hasOwnProperty`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty), [`isPrototypeOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf) and [`propertyIsEnumerable`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable) directly on an object.

#### Rule Details

These methods come from `Object.prototype`, so calling them on an arbitrary object trusts that object: it may shadow the method with a property of the same name, as parsed JSON can, or lack it entirely when it was made with `Object.create(null)`. The rule reports a call of one of the three methods as a member of any object, through dot or bracket access, optional chaining included. Call them through `Object.prototype`, or use `Object.hasOwn(object, key)`. The rule does not fix.

Reimplements [ESLint's `no-prototype-builtins`](https://eslint.org/docs/latest/rules/no-prototype-builtins).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const known = payload.hasOwnProperty('id')
const listed = payload?.['propertyIsEnumerable']('id')
const parent = base.isPrototypeOf(child)
```

##### ✅ Correct

```ts
const known = Object.hasOwn(payload, 'id')
const listed = Object.prototype.propertyIsEnumerable.call(payload, 'id')
const parent = Object.prototype.isPrototypeOf.call(base, child)
```

#### Limitations

The original offers suggestions that rewrite the call through `Object.prototype`; this rule reports without them.

---

### `no-regex-spaces`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid runs of two or more literal spaces in regular expressions.

#### Rule Details

A run of spaces in a pattern is hard to count by eye, so `/a   b/` is easy to misread as two or four spaces. A counted quantifier says how many there are. The rule reports the first run of two or more spaces in a regular expression literal, or in the string pattern of a `RegExp(...)` call with literal flags. Spaces inside a character class are left alone, and when a quantifier follows a run, the last space belongs to it and is not counted.

The fix replaces the run with one space and a count, so three spaces become ` {3}`. It is withheld for a `RegExp` string whose source text spells the pattern differently from its value, for example with escapes, where the offsets would not line up.

Reimplements [ESLint's `no-regex-spaces`](https://eslint.org/docs/latest/rules/no-regex-spaces).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const gap = /total:   \d+/
const built = new RegExp('a   b')
```

##### ✅ Correct

```ts
const gap = /total: {3}\d+/
const classed = /[   ]/
const quantified = /a +b/
```

---

### `no-restricted-imports`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid importing modules, or names from modules, that the configuration restricts.

#### Rule Details

Some modules should not be used in some places: a heavy library with a lighter alternative, a package's internals, a server module in browser code. The rule matches the source of every import, re-export (`export ... from`, `export * from`) and TypeScript `import x = require(...)` against the configured patterns and reports what they restrict. A pattern restricts the whole module, or only some of the names imported from it, or every name except an allowed few. With no patterns configured the rule reports nothing. The rule does not fix.

Patterns are gitignore-style and matched case-insensitively against the module source split at `/`: `*` matches within one segment, `?` one character, `**` any number of segments. A pattern with no slash, or one starting with `**/`, matches at any depth; one with a slash is anchored at the start. A pattern matches a path and everything under it, so a pattern naming lodash also matches `lodash/fp`. A pattern starting with `!` excepts the paths it matches; the last matching pattern of a group wins.

Reimplements [ESLint's `no-restricted-imports`](https://eslint.org/docs/latest/rules/no-restricted-imports), in its [`patterns`](#no-restricted-imports) object form.

#### Options

| Option                 | Type       | Default | Meaning                                               |
| ---------------------- | ---------- | ------- | ----------------------------------------------------- |
| [`patterns`](#no-restricted-imports) | `object[]` | `[]`    | The restrictions, each an object of the fields below. |

| Field                          | Type       | Meaning                                                                                    |
| ------------------------------ | ---------- | ------------------------------------------------------------------------------------------ |
| [`group`](#no-restricted-imports)            | `string[]` | Required. The patterns a module source is matched against.                                 |
| [`importNames`](#no-restricted-imports)      | `string[]` | Only these names are restricted; `default` and `*` name the default and namespace imports. |
| [`allowImportNames`](#no-restricted-imports) | `string[]` | Every name except these is restricted.                                                     |
| [`message`](#no-restricted-imports)          | `string`   | Text appended to the report, such as the alternative to use.                               |

Of the original's options only the object form of [`patterns`](#no-restricted-imports) with these four fields is read. The [`paths`](https://eslint.org/docs/latest/rules/no-restricted-imports#paths) option, string entries in [`patterns`](#no-restricted-imports), and the [`regex`, `caseSensitive`, `importNamePattern`, `allowImportNamePattern` and `allowTypeImports`](https://eslint.org/docs/latest/rules/no-restricted-imports#options) fields are not supported.

#### Examples

##### ❌ Incorrect, with a restricted module

```ts
import merge from 'lodash/merge'
export * from 'lodash'
```

##### ❌ Incorrect, with restricted names

```ts
import React from 'react'
```

##### ✅ Correct, with a restricted module

```ts
import { merge } from 'lodash-es'
import flow from 'lodash/fp'
```

##### ✅ Correct, with restricted names

```ts
import { useState } from 'react'
```

---

### `no-self-assign`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid assigning a variable or property to itself.

#### Rule Details

`value = value` has no effect, and almost always stands where a different name was meant, such as `this.value = value` written as `value = value`. The rule reports the value side of an `=`, `&&=`, `||=` or `??=` assignment that names the same thing as its target: the same variable, the same member chain (`a.b.c = a.b.c`, optional chaining looked through), or a matching position inside array and object destructuring (`[a, b] = [a, c]` reports `a`). Destructuring positions after a spread are not compared, since the spread may change them. The rule does not fix.

Reimplements [ESLint's `no-self-assign`](https://eslint.org/docs/latest/rules/no-self-assign).

#### Options

This rule has no options. The original's [`props`](https://eslint.org/docs/latest/rules/no-self-assign#options) option is not read: properties are always checked, the original's default.

#### Examples

##### ❌ Incorrect

```ts
count = count
config.port = config.port
;[first, second] = [first, third]
```

##### ✅ Correct

```ts
count = next
config.port = other.port
;[first, second] = [second, first]
```

---

### `no-shadow-restricted-names`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid declaring a binding named `undefined`, `NaN`, `Infinity`, [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) or [`eval`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval).

#### Rule Details

These names refer to values and functions the language provides. A local binding of the same name hides them, so `NaN` or `undefined` in that scope no longer means what every reader expects. The rule reports each declaration of one of these names: variables, function and class names, parameters, `catch` parameters and imports. A `let undefined` or `var undefined` declared without an initialiser and never assigned is allowed, since its value is still `undefined`. The rule does not fix.

Reimplements [ESLint's `no-shadow-restricted-names`](https://eslint.org/docs/latest/rules/no-shadow-restricted-names).

#### Options

This rule has no options. The original's [`reportGlobalThis`](https://eslint.org/docs/latest/rules/no-shadow-restricted-names#options) option is not read, and a binding named `globalThis` is never reported.

#### Examples

##### ❌ Incorrect

```ts
const NaN = 0
function check(Infinity: number) {}
const undefined = null
try {
  run()
} catch (undefined) {}
```

##### ✅ Correct

```ts
const notANumber = Number.NaN
function check(limit: number) {}
let undefined
```

---

### `no-sparse-arrays`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid holes in array literals, such as `[1, , 3]`.

#### Rule Details

Two commas with nothing between them leave a hole in the array: the index exists in the length but holds no element, and array methods treat it differently from `undefined`. A hole is easy to miss and is almost always a typo. The rule reports the comma that ends each hole of an array literal; a single trailing comma, as in `[1, 2,]`, is not a hole. Destructuring patterns, where an empty slot skips a value, are not array literals and are not read. The rule does not fix.

Reimplements [ESLint's `no-sparse-arrays`](https://eslint.org/docs/latest/rules/no-sparse-arrays).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const levels = ['low', , 'high']
const leading = [, 1]
```

##### ✅ Correct

```ts
const levels = ['low', undefined, 'high']
const trailing = [1, 2]
const [, second] = levels
```

---

### `no-unexpected-multiline`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid line breaks that make the next line continue the previous expression by accident.

#### Rule Details

Without semicolons, a line that starts with `(`, `[` or a template literal does not start a new statement: it continues the one before it as a call, a property access or a tagged template, which is rarely what the line break meant. The rule reports:

- a call whose `(` starts a new line after the callee, when the call has arguments;
- a computed member access whose `[` starts a new line after the object;
- a tagged template whose literal starts a new line after the tag;
- a division whose operators would read as a regular expression with flags, as in a line `/foo/g.test(x)` after an expression.

Optional calls and accesses (`?.(` and `?.[`) are not reported. Put a semicolon at the start of the continued line, or join the lines when the continuation is meant. The rule does not fix.

Reimplements [ESLint's `no-unexpected-multiline`](https://eslint.org/docs/latest/rules/no-unexpected-multiline).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const value = load
(source).trim()

const first = items
[0].name
```

##### ✅ Correct

```ts
const value = load
;(source).trim()

const first = items[0].name
```

---

### `no-unsafe-finally`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid `return`, `throw`, `break` and `continue` that jump out of a `finally` block.

#### Rule Details

A `finally` block runs after the `try` and `catch` have decided how the statement ends. A jump that leaves the `finally` overrides that decision: a `return` there replaces the value the `try` returned and silently discards an exception being thrown. The rule reports a `return` or `throw` inside a `finally` block, and a `break` or `continue` whose target lies outside it. Jumps that stay inside the block, such as a `break` out of a loop or `switch` written within the `finally`, or a `return` in a function declared inside it, are not reported. The rule does not fix.

Reimplements [ESLint's `no-unsafe-finally`](https://eslint.org/docs/latest/rules/no-unsafe-finally).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
function load(): string {
  try {
    return read()
  } finally {
    return 'fallback'
  }
}
```

##### ✅ Correct

```ts
function load(): string {
  try {
    return read()
  } finally {
    for (const handle of handles) {
      if (handle.closed) break
      handle.close()
    }
  }
}
```

---

### `no-unsafe-optional-chaining`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid using an optional chain where its `undefined` result would throw.

#### Rule Details

An optional chain such as `user?.profile` evaluates to `undefined` when it short-circuits. Used where a value is required, that `undefined` throws a `TypeError`, which defeats the point of the `?.`. The rule reports a chain, possibly behind `&&`, `||`, `??`, a conditional, a sequence or `await`, used as:

- the callee of a call or of `new`, or the tag of a tagged template, as in `(user?.greet)()`;
- the object of a member access, as in `(user?.profile).name`;
- the value destructured by a declaration, an assignment or a default;
- the source of an array or argument spread, or of a `for...of` loop;
- a superclass, or the right side of `in` or `instanceof`.

Continuing the chain with another `?.` is safe and not reported. The rule does not fix.

Reimplements [ESLint's `no-unsafe-optional-chaining`](https://eslint.org/docs/latest/rules/no-unsafe-optional-chaining).

#### Options

This rule has no options. The original's [`disallowArithmeticOperators`](https://eslint.org/docs/latest/rules/no-unsafe-optional-chaining#options) option is not read, so arithmetic on an optional chain, which yields `NaN` rather than throwing, is not reported.

#### Examples

##### ❌ Incorrect

```ts
const name = (user?.profile).name
const { id } = user?.profile
const all = [...user?.roles]
for (const role of user?.roles) {
}
```

##### ✅ Correct

```ts
const name = user?.profile?.name
const { id } = user?.profile ?? {}
const all = [...(user?.roles ?? [])]
```

---

### `no-unused-labels`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid labels that no `break` or `continue` names.

#### Rule Details

A label exists to be the target of a `break` or `continue`. One that nothing targets is noise, and often a sign that the jump it was written for was removed or names a different label. The rule reports every label that no `break` or `continue` inside its statement names. The fix removes the label and its colon, leaving the statement. It is withheld when a comment sits between the label and the statement, or when removing the label would leave a string literal in a position where it would become a directive such as `"use strict"`.

Reimplements [ESLint's `no-unused-labels`](https://eslint.org/docs/latest/rules/no-unused-labels).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
outer: for (const row of rows) {
  if (row.empty) break
}
```

##### ✅ Correct

```ts
outer: for (const row of rows) {
  for (const cell of row.cells) {
    if (cell.done) continue outer
  }
}
```

---

### `no-unused-private-class-members`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid `#private` fields, methods and accessors that the class never reads.

#### Rule Details

A private member can only be used inside its class, so when the class never reads it, it is dead code: left behind by a refactor, or a sign that a read was written against the wrong name. The rule reports each `#name` member of a class that nothing inside the class reads. Writing to a field does not count as a read, and neither does an increment used as a statement (`this.#count++`) or an assignment through destructuring. For a getter or setter every use counts, since using it runs code. Each private name resolves to the nearest enclosing class that declares it. The rule does not fix.

Reimplements [ESLint's `no-unused-private-class-members`](https://eslint.org/docs/latest/rules/no-unused-private-class-members).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
class Counter {
  #count = 0
  #reset() {}

  increment(): void {
    this.#count++
  }
}
```

##### ✅ Correct

```ts
class Counter {
  #count = 0

  increment(): number {
    this.#count += 1
    return this.#count
  }
}
```

#### Limitations

Members marked with TypeScript's [`private`](https://www.typescriptlang.org/docs/handbook/2/classes.html#private) modifier are ordinary properties at run time and are not read by this rule.

---

### `no-useless-assignment`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid assigning a value to a variable that nothing reads before it is overwritten or goes out of scope.

#### Rule Details

A value that is written and then overwritten, or written just before the function ends, does nothing. It is often a bug: the read that should have used it reads a different variable, or a branch that should have returned the value does not. The rule follows the code paths of each function and reports a write, an initialiser included, whose value no read can see before the next write on every path.

Variables that are never read at all are left to [typescript/no-unused-vars](#typescriptno-unused-vars). A variable read from a nested function, or exported from the module, is not checked, since such a read may happen at any time. The rule does not fix.

Reimplements [ESLint's `no-useless-assignment`](https://eslint.org/docs/latest/rules/no-useless-assignment).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
function label(count: number): string {
  let text = 'none'
  text = count > 1 ? 'many' : 'one'
  return text
}

function total(items: number[]): number {
  let sum = 0
  for (const item of items) sum += item
  sum = 0
  return items.length
}
```

##### ✅ Correct

```ts
function label(count: number): string {
  let text = 'none'
  if (count > 0) text = count > 1 ? 'many' : 'one'
  return text
}
```

---

### `no-useless-backreference`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid backreferences in regular expressions that can only ever match the empty string.

#### Rule Details

A backreference such as `\1` or `\k<name>` matches what its group captured. When the group cannot have matched yet, or its match has been thrown away, the backreference silently matches the empty string, which is never what it was written for. The rule reports a backreference, in a regular expression literal or the string pattern of a `RegExp(...)` call, that refers to:

- the group that contains it, as in `/(a\1)/`;
- a group later in the pattern, as in `/\1(a)/`;
- a group before it while both sit in a lookbehind, which matches right to left;
- a group in another alternative, as in `/(a)|\1b/`;
- a group inside a negative lookahead or lookbehind that the backreference sits outside of.

The message names the group and the reason. The rule does not fix.

Reimplements [ESLint's `no-useless-backreference`](https://eslint.org/docs/latest/rules/no-useless-backreference).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const nested = /(a\1)/
const forward = /\1(a)/
const alternative = /(a)|\1b/
const negated = /(?!(a))\1/
```

##### ✅ Correct

```ts
const repeated = /(a)\1/
const named = /(?<quote>['"]).*\k<quote>/
const behind = /(?<=\1(a))b/
```

---

### `no-useless-catch`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid `catch` clauses that only rethrow the error they caught.

#### Rule Details

A `catch (error) { throw error }` changes nothing: the error propagates exactly as it would without the clause. The rule reports a `catch` clause whose first statement rethrows its own parameter. Without a `finally`, the whole `try` statement is reported, since the `try` itself is then noise; with one, only the `catch` clause is reported, since the `finally` still justifies the `try`. A clause that does anything before rethrowing, such as logging or wrapping the error, is not reported. The rule does not fix.

Reimplements [ESLint's `no-useless-catch`](https://eslint.org/docs/latest/rules/no-useless-catch).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
try {
  run()
} catch (error) {
  throw error
}

try {
  run()
} catch (error) {
  throw error
} finally {
  cleanUp()
}
```

##### ✅ Correct

```ts
try {
  run()
} catch (error) {
  log(error)
  throw error
}

try {
  run()
} finally {
  cleanUp()
}
```

---

### `no-useless-escape`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid backslashes before characters that need no escaping.

#### Rule Details

An unnecessary backslash is noise, and it makes the escapes that do matter harder to spot. The rule reports each such backslash:

- in a regular expression literal, before a character the pattern grammar reads the same way bare, with the rules of character classes and of the `v` flag applied, so `/\-/` outside a class and `/[\.]/` are reported while `/\./` and `/[a\-z]/` are not;
- in a string literal, before a character that is not an escape and not the string's own quote;
- in a template literal, and in a TypeScript template literal type, before a character that is not an escape, a backtick, or the `$` that would open a substitution.

Tagged templates are skipped, since the tag sees the raw text, and so are JSX attribute strings. The rule does not fix.

Reimplements [ESLint's `no-useless-escape`](https://eslint.org/docs/latest/rules/no-useless-escape).

#### Options

This rule has no options. The original's [`allowRegexCharacters`](https://eslint.org/docs/latest/rules/no-useless-escape#options) option is not read.

#### Examples

##### ❌ Incorrect

```ts
const quote = "it\'s"
const dash = /\-/
const dot = /[\.]/
const template = `\d`
```

##### ✅ Correct

```ts
const quote = "it's"
const escaped = 'it\'s'
const dot = /\./
const range = /[a\-z]/
const template = `\${literal}`
```

#### Limitations

The original offers suggestions that remove the backslash or double it; this rule reports without them. Patterns passed to `RegExp(...)` as strings are read only as strings.

---

### `no-var`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require `let` or `const` instead of `var`.

#### Rule Details

A `var` is scoped to its whole function rather than to its block, is hoisted above its declaration, and may be redeclared, so it leaks out of loops and conditionals in ways `let` and `const` do not. The rule reports every `var` declaration, except one inside a `declare global` block, where TypeScript only accepts `var`.

The fix turns `var` into `let` only where the change keeps the program's meaning: the variable is declared once, used only inside its block and after its declaration, does not become a property of the global object at the top level of a script, and is not a loop variable a closure captures, where `let` would create a binding per iteration. Choosing `const` is left to [prefer-const](#prefer-const).

Reimplements [ESLint's `no-var`](https://eslint.org/docs/latest/rules/no-var).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
var count = 0
count += 1

function find(items: string[]): number {
  for (var index = 0; index < items.length; index++) {
    if (items[index] === 'x') break
  }
  return index
}
```

##### ✅ Correct

```ts
let count = 0
count += 1

declare global {
  var registry: string[]
}
```

---

### `prefer-const`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require `const` for `let` variables that are never reassigned.

#### Rule Details

A `let` that is assigned once and never again is a constant in all but name. Declaring it `const` tells the reader the binding will not change and makes an accidental reassignment an error. The rule reports each `let` variable written exactly once, by its initialiser or by a single later assignment in the same scope, and read after that. A destructuring is judged variable by variable, so `let { a, b } = options` reports `a` alone when only `b` is reassigned. The counter declared in the head of a classic `for` loop is never reported; the variable of a `for...of` or `for...in` loop is.

The fix rewrites `let` as `const`. It is offered only when every variable of the declaration qualifies and the declaration initialises each of them, or heads a `for...of` or `for...in` loop; a variable declared without a value and assigned later is reported without a fix.

Reimplements [ESLint's `prefer-const`](https://eslint.org/docs/latest/rules/prefer-const).

#### Options

This rule has no options. The original's options are not read: [`destructuring`](https://eslint.org/docs/latest/rules/prefer-const#options) is fixed to `"any"` and [`ignoreReadBeforeAssign`](https://eslint.org/docs/latest/rules/prefer-const#options) to `false`, the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
let total = compute()
print(total)

for (let item of items) {
  print(item)
}

let { port, host } = options
host = 'localhost'
print(port, host)
```

##### ✅ Correct

```ts
const total = compute()
print(total)

let count = 0
count += 1

for (let index = 0; index < 3; print(index)) {}
```

---

### `prefer-rest-params`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require rest parameters instead of the [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) object.

#### Rule Details

[`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) is an array-like object, not an array, so it lacks the array methods, it hides which parameters a function takes, and arrow functions do not have one of their own. A rest parameter, `(...items)`, is a real array and shows in the signature. The rule reports each use of the implicit [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) inside a function declaration or expression. Reading a property by name, such as [`arguments.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/length), is allowed, and so is a function that declares its own binding called [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments). The rule does not fix.

Reimplements [ESLint's `prefer-rest-params`](https://eslint.org/docs/latest/rules/prefer-rest-params).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
function sum() {
  return Array.from(arguments).reduce((total, value) => total + value, 0)
}

function first() {
  return arguments[0]
}
```

##### ✅ Correct

```ts
function sum(...values: number[]) {
  return values.reduce((total, value) => total + value, 0)
}

function count() {
  return arguments.length
}
```

---

### `prefer-spread`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require spread syntax instead of `.apply()` to call a function with an array of arguments.

#### Rule Details

`fn.apply(null, args)` was the way to call a function with an array of arguments before spread syntax existed. `fn(...args)` says the same thing directly and does not make the reader check the `this` argument. The rule reports a two-argument `.apply(...)` call that spread can replace exactly: one whose `this` argument is `null`, `undefined` or `void 0` for a plain function, or the same object the method is read from, as in `math.max.apply(math, values)`. Calls whose argument list is an array literal, and calls that pass a different `this`, are left alone. The rule does not fix.

Reimplements [ESLint's `prefer-spread`](https://eslint.org/docs/latest/rules/prefer-spread).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const largest = max.apply(null, values)
const joined = parts.push.apply(parts, extra)
```

##### ✅ Correct

```ts
const largest = max(...values)
parts.push(...extra)
const bound = handler.apply(context, values)
```

---

### `require-yield`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require generator functions with a body to contain `yield`.

#### Rule Details

A generator that never yields produces an iterator that finishes at once, with its return value as the only result. That is rarely the intent: either a `yield` is missing, or the function was meant to be an ordinary one. The rule reports a generator function declaration or expression, generator methods included, whose body has statements but no `yield`. An empty generator, `function* () {}`, is allowed, since it is a deliberate empty iterator. The rule does not fix.

Reimplements [ESLint's `require-yield`](https://eslint.org/docs/latest/rules/require-yield).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
function* ids() {
  return [1, 2, 3]
}
```

##### ✅ Correct

```ts
function* ids() {
  yield 1
  yield 2
}

function* none() {}
```

---

### `use-isnan`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require `Number.isNaN()` instead of comparing with `NaN`.

#### Rule Details

`NaN` is the one value that is not equal to itself, so `value === NaN` is always false and `value !== NaN` always true, whatever the value. The rule reports a comparison (`==`, `===`, `!=`, `!==`, `<`, `>`, `<=`, `>=`) with `NaN` or `Number.NaN` on either side. By default it also reports `switch (NaN)` and `case NaN:`, which can never match for the same reason. Use `Number.isNaN(value)`. The rule does not fix.

Reimplements [ESLint's `use-isnan`](https://eslint.org/docs/latest/rules/use-isnan).

#### Options

| Option                             | Type      | Default | Meaning                                              |
| ---------------------------------- | --------- | ------- | ---------------------------------------------------- |
| [`enforceForSwitchCase`](#use-isnan) | `boolean` | `true`  | Whether `switch (NaN)` and `case NaN:` are reported. |

The original's [`enforceForIndexOf`](https://eslint.org/docs/latest/rules/use-isnan#enforceforindexof) option is not read, so `indexOf(NaN)` and `lastIndexOf(NaN)` are not reported.

#### Examples

##### ❌ Incorrect

```ts
if (value === NaN) {
  reset()
}

switch (value) {
  case NaN:
    reset()
}
```

##### ✅ Correct

```ts
if (Number.isNaN(value)) {
  reset()
}
```

##### ✅ Correct, with { "enforceForSwitchCase": false }

```ts
switch (value) {
  case NaN:
    reset()
}
```

#### Limitations

The original offers suggestions that rewrite a comparison as a `Number.isNaN()` call; this rule reports without them.

---

### `valid-typeof`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require `typeof` to be compared with one of the strings it can produce.

#### Rule Details

`typeof` yields one of eight strings: `"undefined"`, `"object"`, `"boolean"`, `"number"`, `"bigint"`, `"string"`, `"symbol"` and `"function"`. A comparison with anything else, usually a misspelling such as `"strnig"` or a guess such as `"array"`, can never hold. The rule reports the other side of an `==`, `===`, `!=` or `!==` comparison with a `typeof` expression when it is a literal, or a template without substitutions, that is not one of those strings, and when it is the global `undefined` rather than the string `"undefined"`. The rule does not fix.

Reimplements [ESLint's `valid-typeof`](https://eslint.org/docs/latest/rules/valid-typeof).

#### Options

This rule has no options. The original's [`requireStringLiterals`](https://eslint.org/docs/latest/rules/valid-typeof#options) option is not read, so a comparison with a variable or another expression is never reported.

#### Examples

##### ❌ Incorrect

```ts
const isText = typeof value === 'strnig'
const isList = typeof value === 'array'
const isMissing = typeof value === undefined
```

##### ✅ Correct

```ts
const isText = typeof value === 'string'
const isList = Array.isArray(value)
const isMissing = typeof value === 'undefined'
const isSame = typeof value === typeof other
```

#### Limitations

The original offers a suggestion that turns a comparison with `undefined` into one with the string; this rule reports without it.

## TypeScript rules

Reimplemented from [typescript-eslint](https://typescript-eslint.io/rules/), without type information. [`CODE_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-CODE_RULES) turns on the ones its `recommended` configuration does.

| Rule | Reads | 🔧 | `CODE_RULES` |
| ---- | ----- | :-: | :-: |
| [`typescript/adjacent-overload-signatures`](#typescriptadjacent-overload-signatures) | TypeScript, JavaScript |  | ✅ |
| [`typescript/ban-ts-comment`](#typescriptban-ts-comment) | TypeScript, JavaScript |  | ✅ |
| [`typescript/consistent-type-assertions`](#typescriptconsistent-type-assertions) | TypeScript, JavaScript | 🔧 |  |
| [`typescript/consistent-type-imports`](#typescriptconsistent-type-imports) | TypeScript, JavaScript | 🔧 |  |
| [`typescript/no-array-constructor`](#typescriptno-array-constructor) | TypeScript, JavaScript | 🔧 | ✅ |
| [`typescript/no-duplicate-enum-values`](#typescriptno-duplicate-enum-values) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-empty-function`](#typescriptno-empty-function) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-empty-interface`](#typescriptno-empty-interface) | TypeScript, JavaScript | 🔧 | ✅ |
| [`typescript/no-empty-object-type`](#typescriptno-empty-object-type) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-explicit-any`](#typescriptno-explicit-any) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-extra-non-null-assertion`](#typescriptno-extra-non-null-assertion) | TypeScript, JavaScript | 🔧 | ✅ |
| [`typescript/no-inferrable-types`](#typescriptno-inferrable-types) | TypeScript, JavaScript | 🔧 | ✅ |
| [`typescript/no-misused-new`](#typescriptno-misused-new) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-namespace`](#typescriptno-namespace) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-non-null-asserted-optional-chain`](#typescriptno-non-null-asserted-optional-chain) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-non-null-assertion`](#typescriptno-non-null-assertion) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-this-alias`](#typescriptno-this-alias) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-unnecessary-type-constraint`](#typescriptno-unnecessary-type-constraint) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-unsafe-declaration-merging`](#typescriptno-unsafe-declaration-merging) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-unsafe-function-type`](#typescriptno-unsafe-function-type) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-unused-expressions`](#typescriptno-unused-expressions) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-unused-vars`](#typescriptno-unused-vars) | TypeScript, JavaScript |  | ✅ |
| [`typescript/no-wrapper-object-types`](#typescriptno-wrapper-object-types) | TypeScript, JavaScript | 🔧 | ✅ |
| [`typescript/prefer-as-const`](#typescriptprefer-as-const) | TypeScript, JavaScript | 🔧 | ✅ |
| [`typescript/prefer-namespace-keyword`](#typescriptprefer-namespace-keyword) | TypeScript, JavaScript | 🔧 | ✅ |
| [`typescript/triple-slash-reference`](#typescripttriple-slash-reference) | TypeScript, JavaScript |  | ✅ |

---

### `typescript/adjacent-overload-signatures`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require the overload signatures of a function, method or constructor to sit next to each other.

#### Rule Details

Overloads read as one unit only when they are declared together. This rule reports a signature that repeats a name already seen in the same body after some other member came in between. It checks top-level statements, blocks, namespaces, classes, interfaces and type literals, and keeps static and instance members, quoted and bare names, and private names apart. It does not fix.

Reimplements [typescript-eslint's `adjacent-overload-signatures`](https://typescript-eslint.io/rules/adjacent-overload-signatures).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
interface Store {
  get(key: string): string
  set(key: string, value: string): void
  get(key: number): string
}
```

##### ✅ Correct

```ts
interface Store {
  get(key: string): string
  get(key: number): string
  set(key: string, value: string): void
}
```

---

### `typescript/ban-ts-comment`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid `@ts-ignore` and `@ts-nocheck`, and require a description on `@ts-expect-error`.

#### Rule Details

A `@ts-` directive changes what the compiler reports, so each one should be deliberate and explained. This rule reports `@ts-ignore` in favour of `@ts-expect-error`, which fails once the line it covers stops erroring. It reports a `@ts-expect-error` whose description is shorter than three characters, counted as graphemes. It reports `@ts-nocheck` only where the compiler honours it, before the first statement of the file, and leaves `@ts-check` alone. It does not fix.

Reimplements [typescript-eslint's `ban-ts-comment`](https://typescript-eslint.io/rules/ban-ts-comment).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/ban-ts-comment/#options), which allow or require a description per directive, set a description format and change the minimum length, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
// @ts-ignore
const port: number = '8080'
```

```ts
// @ts-expect-error
const port: number = '8080'
```

##### ✅ Correct

```ts
// @ts-expect-error: the fixture checks the runtime guard
const port: number = '8080'
```

#### Limitations

The original offers a suggestion that rewrites `@ts-ignore` to `@ts-expect-error`; this rule reports without one.

---

### `typescript/consistent-type-assertions`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require type assertions to be written `value as Type` rather than `<Type>value`.

#### Rule Details

The angle-bracket form reads like JSX and cannot be written in a `.tsx` file at all, so one assertion style keeps code portable between the two. This rule reports every angle-bracket assertion. The fix rewrites it to the `as` form and keeps the meaning: it parenthesises the value when the value binds no tighter than `as`, and parenthesises the whole assertion when the surrounding expression binds at least as tight, unless it already sits in parentheses of its own.

Reimplements [typescript-eslint's `consistent-type-assertions`](https://typescript-eslint.io/rules/consistent-type-assertions).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/consistent-type-assertions/#options), which choose the angle-bracket style or forbid assertions, and restrict assertions on object and array literals, are not read: the style is fixed to `as` and literals are not checked.

#### Examples

##### ❌ Incorrect

```ts
const input = <HTMLInputElement>event.target
const total = <number>(a ?? b) + 1
```

##### ✅ Correct

```ts
const input = event.target as HTMLInputElement
const total = ((a ?? b) as number) + 1
```

---

### `typescript/consistent-type-imports`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require `import type` for imports used only as types, and forbid `import()` type annotations.

#### Rule Details

A type-only import is erased by the compiler, so marking it keeps the emitted module free of imports it never needs. This rule reports a value import declaration whose bindings are used only in type positions, including `typeof` queries and computed keys of property signatures. A re-exported binding counts as a value use. A declaration with import attributes is left alone. The fix adds `type` when every binding is type-only, and otherwise moves the type-only bindings to a separate `import type` of the same module, joining one that already exists. The rule also reports `import('...')` used as a type annotation, without a fix.

Reimplements [typescript-eslint's `consistent-type-imports`](https://typescript-eslint.io/rules/consistent-type-imports).

#### Options

| Option                                                                                                           | Type                      | Default                   | Meaning                                     |
| ---------------------------------------------------------------------------------------------------------------- | ------------------------- | ------------------------- | ------------------------------------------- |
| [`disallowTypeAnnotations`](https://typescript-eslint.io/rules/consistent-type-imports/#disallowtypeannotations) | boolean                   | true                      | Report `import()` type annotations.         |
| [`prefer`](https://typescript-eslint.io/rules/consistent-type-imports/#prefer)                                   | `'type-imports'`          | `'type-imports'`          | Accepted for compatibility; the only value. |
| [`fixStyle`](https://typescript-eslint.io/rules/consistent-type-imports/#fixstyle)                               | `'separate-type-imports'` | `'separate-type-imports'` | Accepted for compatibility; the only value. |

The original's `'no-type-imports'` preference and `'inline-type-imports'` fix style are not supported.

#### Examples

##### ❌ Incorrect

```ts
import { Config, load } from './config'

export const read = (path: string): Config => load(path)
```

```ts
let config: import('./config').Config
```

##### ✅ Correct

```ts
import type { Config } from './config'
import { load } from './config'

export const read = (path: string): Config => load(path)
```

#### Limitations

The original keeps value imports that decorator metadata needs when [`emitDecoratorMetadata`](https://www.typescriptlang.org/tsconfig/#emitDecoratorMetadata) and [`experimentalDecorators`](https://www.typescriptlang.org/tsconfig/#experimentalDecorators) are on. This rule does not read compiler options, so in that setup a class used only in decorated signatures is still reported.

---

### `typescript/no-array-constructor`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid building arrays with the `Array` constructor where a literal says the same.

#### Rule Details

`Array(a, b)` and `new Array()` produce what `[a, b]` and `[]` spell out directly, and the constructor's behaviour changes with the number of arguments. This rule reports calls and constructions of `Array` with zero or several arguments. A single argument sets a length, so that form is allowed, and so is a call with type arguments such as `new Array<string>()`, which a literal cannot express. The fix replaces the call with a literal holding the argument text, comments included.

Reimplements [typescript-eslint's `no-array-constructor`](https://typescript-eslint.io/rules/no-array-constructor).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const empty = new Array()
const pair = Array(1, 2)
```

##### ✅ Correct

```ts
const empty = []
const pair = [1, 2]
const slots = new Array(3)
const names = new Array<string>()
```

#### Limitations

The rule matches the name `Array` and does not check whether a local binding shadows the global.

---

### `typescript/no-duplicate-enum-values`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid two members of one enum from having the same literal value.

#### Rule Details

An enum member that repeats another's value is almost always a copied line that was not edited, and it makes the two names indistinguishable at run time. This rule reports every member whose initializer repeats a value seen earlier in the same enum. Values are compared when they are string or number literals, templates without substitutions, or numbers under a unary plus or minus. Strings and numbers never collide with each other, and `-0` is distinct from `0`. Members without initializers and computed values are not compared. It does not fix.

Reimplements [typescript-eslint's `no-duplicate-enum-values`](https://typescript-eslint.io/rules/no-duplicate-enum-values).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
enum Status {
  Active = 'active',
  Paused = 'active',
}
```

##### ✅ Correct

```ts
enum Status {
  Active = 'active',
  Paused = 'paused',
}
```

---

### `typescript/no-empty-function`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid functions whose body is empty.

#### Rule Details

An empty function body is either unfinished work or a deliberate no-op, and a reader cannot tell which. This rule reports a function declaration, function expression, arrow function, method, getter, setter or constructor whose block body holds neither a statement nor a comment. A comment inside the body, such as one saying why nothing happens, is enough to pass. A constructor that declares parameter properties passes too, since its parameter list does the work. It does not fix.

Reimplements [typescript-eslint's `no-empty-function`](https://typescript-eslint.io/rules/no-empty-function).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/no-empty-function/#options), a list of function kinds to allow, are not read: every kind is checked.

#### Examples

##### ❌ Incorrect

```ts
function noop() {}

class Store {
  reset() {}
}
```

##### ✅ Correct

```ts
function noop() {
  // intentionally empty: callers pass it where a handler is required
}

class Store {
  constructor(private readonly name: string) {}
}
```

---

### `typescript/no-empty-interface`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid interfaces that declare no members.

#### Rule Details

An interface without members is the same as `{}`, which accepts any value except `null` and `undefined`, and an empty interface that extends one type is just that type under another name. This rule reports both. An empty interface extending two or more types passes, since it names their combination. The fix rewrites the single-supertype case as a type alias, keeping the type parameters; it is withheld when the interface merges with a class of the same name, or is declared inside an ambient module of a declaration file, where an alias would change meaning. The memberless case without a supertype has no fix.

Reimplements [typescript-eslint's `no-empty-interface`](https://typescript-eslint.io/rules/no-empty-interface), which typescript-eslint has since folded into [`no-empty-object-type`](#typescriptno-empty-object-type).

#### Options

This rule has no options. The original's [`allowSingleExtends`](https://typescript-eslint.io/rules/no-empty-interface/#options) option is not read: an empty interface extending one type is always reported.

#### Examples

##### ❌ Incorrect

```ts
interface Props {}

interface ButtonProps extends Props {}
```

##### ✅ Correct

```ts
type ButtonProps = Props

interface LinkProps extends Props, Anchor {}

interface Props {
  label: string
}
```

#### Limitations

Where the fix is withheld, the original offers the type alias as a suggestion; this rule reports without one.

---

### `typescript/no-empty-object-type`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid the empty object type, written `{}` or as an interface without members.

#### Rule Details

The type `{}` accepts every value except `null` and `undefined`, literals such as `0` and `""` included, which is rarely what its author meant: `object` says "any object" and `unknown` says "any value". This rule reports a `{}` type literal and an interface that declares no members and extends nothing. An interface that declares no members and extends exactly one type is reported as equivalent to that type; one extending two or more passes. A `{}` inside an intersection passes, since `T & {}` is the idiom for a non-nullable `T`. It does not fix.

Reimplements [typescript-eslint's `no-empty-object-type`](https://typescript-eslint.io/rules/no-empty-object-type).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/no-empty-object-type/#options), which allow empty interfaces, allow `{}` literals or exempt names matching a pattern, are not read, although the report text still names the option that would allow the construct upstream.

#### Examples

##### ❌ Incorrect

```ts
let value: {}

interface Props {}

interface ButtonProps extends Props {}
```

##### ✅ Correct

```ts
let value: object
let anything: unknown

type NonNullable<T> = T & {}

interface LinkProps extends Props, Anchor {}
```

#### Limitations

The original offers suggestions that replace `{}` with `object` or `unknown`, and that turn a single-supertype interface into a type alias; this rule reports without them.

---

### `typescript/no-explicit-any`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid writing the `any` type.

#### Rule Details

The `any` type switches type checking off for every value it touches, and the loss spreads through whatever the value flows into. This rule reports every `any` written in a type position, so that a precise type is chosen, or `unknown` where the type really is not known and must be narrowed before use. It does not fix.

Reimplements [typescript-eslint's `no-explicit-any`](https://typescript-eslint.io/rules/no-explicit-any).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/no-explicit-any/#options), which offer an `unknown` fix and exempt `any[]` in rest parameters, are not read.

#### Examples

##### ❌ Incorrect

```ts
function parse(text: string): any {
  return JSON.parse(text)
}
```

##### ✅ Correct

```ts
function parse(text: string): unknown {
  return JSON.parse(text)
}
```

#### Limitations

The original offers suggestions that replace `any` with `unknown` or `never`; this rule reports without them.

---

### `typescript/no-extra-non-null-assertion`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid non-null assertions that have no effect.

#### Rule Details

A second `!` on an already asserted value changes nothing, and a `!` directly before an optional chain contradicts it: the assertion says the value is never nullish while `?.` says it may be. This rule reports a non-null assertion that is asserted again, or that is the object of an optional member access or the callee of an optional call. The fix removes the extra `!`.

Reimplements [typescript-eslint's `no-extra-non-null-assertion`](https://typescript-eslint.io/rules/no-extra-non-null-assertion).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const name = user!!.name
const size = list!?.length
const result = handler!?.()
```

##### ✅ Correct

```ts
const name = user!.name
const size = list?.length
const result = handler?.()
```

---

### `typescript/no-inferrable-types`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid type annotations that repeat the type of a literal initializer.

#### Rule Details

`const count: number = 0` says twice what `const count = 0` says once. This rule reports an annotation of `bigint`, `boolean`, `null`, `number`, `string`, `symbol`, `undefined` or `RegExp` on a variable, a parameter with a default, or a class property, when the initializer is plainly a value of that type: a literal, a template, a negated or signed number, `!x`, `void x`, `NaN`, `Infinity`, or a call of the matching global such as `String(x)` or `new RegExp(x)`. Readonly and optional properties are left alone, since there the annotation widens a literal type. The fix removes the annotation, together with the `?` of an optional parameter or the `!` of a definite property that would be left dangling.

Reimplements [typescript-eslint's `no-inferrable-types`](https://typescript-eslint.io/rules/no-inferrable-types).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/no-inferrable-types/#options), which exempt parameters or properties, are not read: both are always checked.

#### Examples

##### ❌ Incorrect

```ts
const retries: number = 3
const label: string = `retry ${retries}`

function wait(ms: number = 100) {
  return ms
}
```

##### ✅ Correct

```ts
const retries = 3
const label = `retry ${retries}`

function wait(ms = 100) {
  return ms
}
```

---

### `typescript/no-misused-new`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid `new` in classes and [`constructor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor) in interfaces, where the two have been confused.

#### Rule Details

A class declares its constructor with [`constructor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor), and an interface describes construction with a `new` signature. This rule reports an interface construct signature that returns the interface itself, an interface member named [`constructor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor), and a bodiless class method named `new` that returns the class. Each of these compiles but does not describe what its author meant. It does not fix.

Reimplements [typescript-eslint's `no-misused-new`](https://typescript-eslint.io/rules/no-misused-new).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
interface Point {
  new (x: number, y: number): Point
  constructor(): void
}

declare class Vector {
  new(): Vector
}
```

##### ✅ Correct

```ts
interface PointConstructor {
  new (x: number, y: number): Point
}

declare class Vector {
  constructor()
}
```

---

### `typescript/no-namespace`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid TypeScript namespaces and `module Name` blocks outside declaration files.

#### Rule Details

ES modules already give every file its own scope and an explicit import and export surface, so a namespace adds a second, older way to group code. This rule reports every `namespace Name {}` and `module Name {}` declaration in a source file. Declaration files (`.d.ts`) are exempt, since ambient namespaces there describe globals that already exist. A `declare global {}` augmentation and an ambient module named by a string, such as `declare module 'pkg' {}`, pass everywhere. It does not fix.

Reimplements [typescript-eslint's `no-namespace`](https://typescript-eslint.io/rules/no-namespace).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/no-namespace/#options), which allow `declare` namespaces in source files or turn off the declaration-file exemption, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
namespace Geometry {
  export const origin = { x: 0, y: 0 }
}
```

##### ✅ Correct

```ts
export const origin = { x: 0, y: 0 }

declare module 'legacy-lib' {
  export const version: string
}

declare global {
  interface Window {
    analytics: unknown
  }
}
```

---

### `typescript/no-non-null-asserted-optional-chain`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid a non-null assertion on the result of an optional chain.

#### Rule Details

An optional chain evaluates to `undefined` when a link is missing, by design. A `!` after the chain, or after the chain in parentheses, tells the compiler that cannot happen, which hides exactly the case the chain was written to handle. This rule reports both shapes. It does not fix: drop the `!` and handle `undefined`, or drop the `?.` if the value is known to exist.

Reimplements [typescript-eslint's `no-non-null-asserted-optional-chain`](https://typescript-eslint.io/rules/no-non-null-asserted-optional-chain).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const city = user?.address!
const zip = (user?.address)!.zip
```

##### ✅ Correct

```ts
const city = user?.address
const zip = user!.address.zip
```

#### Limitations

The original offers a suggestion that removes the `!`; this rule reports without one.

---

### `typescript/no-non-null-assertion`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid the non-null assertion operator `!`.

#### Rule Details

A postfix `!` tells the compiler a value is never `null` or `undefined` without checking, so a wrong assumption surfaces as a runtime error far from its cause. This rule reports every non-null assertion. It does not fix: narrow the value with a check, use optional chaining, or give it a type that cannot be nullish.

Reimplements [typescript-eslint's `no-non-null-assertion`](https://typescript-eslint.io/rules/no-non-null-assertion).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const root = document.getElementById('root')!
root.append('ready')
```

##### ✅ Correct

```ts
const root = document.getElementById('root')
if (root !== null) root.append('ready')
```

#### Limitations

The original offers suggestions that replace `x!.y` with `x?.y`; this rule reports without them.

---

### `typescript/no-this-alias`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid copying `this` into a variable.

#### Rule Details

Storing `this` in a variable such as self or that is a habit from before arrow functions, which keep the surrounding `this` without a copy. This rule reports a variable declaration or an assignment whose target is a plain identifier and whose value is `this`. Destructuring members out of `this` passes. It does not fix.

Reimplements [typescript-eslint's `no-this-alias`](https://typescript-eslint.io/rules/no-this-alias).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/no-this-alias/#options), which forbid destructuring and allow chosen alias names, are not read: destructuring always passes and no name is allowed.

#### Examples

##### ❌ Incorrect

```ts
class Timer {
  start() {
    const self = this
    setTimeout(function () {
      self.tick()
    }, 1000)
  }
}
```

##### ✅ Correct

```ts
class Timer {
  start() {
    const { tick } = this
    setTimeout(() => this.tick(), 1000)
  }
}
```

---

### `typescript/no-unnecessary-type-constraint`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid constraining a type parameter to `any` or `unknown`.

#### Rule Details

A type parameter without a constraint already accepts every type, so `extends any` and `extends unknown` add nothing but noise. This rule reports every type parameter declared with one of those two constraints, on functions, classes, interfaces, type aliases and methods alike. It does not fix: delete the constraint.

Reimplements [typescript-eslint's `no-unnecessary-type-constraint`](https://typescript-eslint.io/rules/no-unnecessary-type-constraint).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
function first<T extends unknown>(items: T[]): T | undefined {
  return items[0]
}

interface Box<T extends any> {
  value: T
}
```

##### ✅ Correct

```ts
function first<T>(items: T[]): T | undefined {
  return items[0]
}

interface Box<T extends object> {
  value: T
}
```

#### Limitations

The original offers a suggestion that removes the constraint, keeping `<T,>` in a `.tsx` arrow function; this rule reports without one.

---

### `typescript/no-unsafe-declaration-merging`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid a class and an interface of the same name in one scope.

#### Rule Details

When a class and an interface share a name, TypeScript merges them: the interface's members join the class's type, but the class never has to implement them, so the compiler accepts calls that fail at run time. This rule reports both declarations of such a pair. A class whose name is merged only with a namespace, or an interface merged only with another interface, passes. It does not fix.

Reimplements [typescript-eslint's `no-unsafe-declaration-merging`](https://typescript-eslint.io/rules/no-unsafe-declaration-merging).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
interface Logger {
  flush(): void
}

class Logger {
  log(message: string) {
    return message
  }
}
```

##### ✅ Correct

```ts
interface Flushable {
  flush(): void
}

class Logger implements Flushable {
  flush() {
    return undefined
  }
}
```

---

### `typescript/no-unsafe-function-type`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid the global `Function` type.

#### Rule Details

The built-in `Function` type accepts any callable, including classes, and types every call through it as returning `any`, so neither the arguments nor the result are checked. This rule reports `Function` used as a type, and in the `extends` of an interface or the `implements` of a class, when it refers to the global. A type named `Function` that the file declares or imports itself passes. It does not fix: write a function type with its parameters and return type.

Reimplements [typescript-eslint's `no-unsafe-function-type`](https://typescript-eslint.io/rules/no-unsafe-function-type).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
function retry(task: Function, times: number) {
  return task
}
```

##### ✅ Correct

```ts
function retry(task: () => Promise<void>, times: number) {
  return task
}
```

---

### `typescript/no-unused-expressions`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid expression statements whose value is thrown away.

#### Rule Details

A statement that neither calls, assigns, awaits, yields, deletes nor uses `void` does nothing with the value it computes, which is usually a typo or a half-finished edit. This rule reports a statement made of a literal, a name, a member access, a binary, logical, conditional or unary operator, a sequence, an array, object, function or class expression, a template or a tagged template. Type assertions, non-null assertions, instantiation expressions and optional chains are looked through to the expression underneath. Directive prologue strings such as `'use strict'`, dynamic imports and JSX elements pass. It does not fix.

Reimplements [typescript-eslint's `no-unused-expressions`](https://typescript-eslint.io/rules/no-unused-expressions).

#### Options

This rule has no options. The [original's options](https://eslint.org/docs/latest/rules/no-unused-expressions#options), which allow short-circuit and ternary expressions, allow tagged templates and check JSX, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
config.enabled
ready && start()
count > 0 ? show() : hide()
user!.name as string
```

##### ✅ Correct

```ts
'use strict'
start()
config.enabled = true
if (ready) start()
void import('./plugin')
```

---

### `typescript/no-unused-vars`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid variables, parameters, imports, types and namespaces that are declared and never used.

#### Rule Details

A declaration nothing reads is dead code or a sign of a mistake, such as a misspelt name or a forgotten call. This rule reports it at the declaration, or at its last write in its own scope when it is only ever assigned. A read that serves only the variable's own update, such as `count += 1` as a statement, does not count as a use, and neither does a function or type referring to itself. A value read only inside `typeof` queries is reported as used only as a type, unless it is an import. Exported declarations count as used, as do the declarations of a declaration file or a `declare namespace` that has no explicit export list. It does not fix.

Parameters before the last used one, setter parameters, parameters of signatures and function types, constructor parameter properties, enum members and mapped type keys are never reported. Unused `catch` bindings and properties destructured beside a rest element are reported.

Reimplements [typescript-eslint's `no-unused-vars`](https://typescript-eslint.io/rules/no-unused-vars).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/no-unused-vars/#options), among them the ignore patterns for names such as a leading underscore, the parameter and caught-error modes, and the rest-sibling exemption, are not read: the behaviour is fixed to the original's defaults, with no ignore pattern.

#### Examples

##### ❌ Incorrect

```ts
import { readFileSync } from 'node:fs'

let attempts = 0
attempts += 1

export function greet(name: string, _unused: number) {
  const greeting = `Hello, ${name}`
}
```

##### ✅ Correct

```ts
import { readFileSync } from 'node:fs'

export function load(_path: string, encoding: BufferEncoding) {
  return readFileSync('config.json', encoding)
}
```

---

### `typescript/no-wrapper-object-types`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid the wrapper object types `String`, `Number`, `Boolean`, `BigInt`, `Symbol` and `Object` as types.

#### Rule Details

The upper-cased wrapper types describe boxed objects, not the primitives almost every value is: a `string` is not assignable from a `String`, and `Object` admits every value except `null` and `undefined`. This rule reports each wrapper used as a type, or in the `extends` of an interface or the `implements` of a class, when the name refers to the global. A type of the same name that the file declares or imports itself passes. The fix replaces a type reference with the lower-cased primitive (`Object` becomes `object`); a heritage clause is reported without a fix.

Reimplements [typescript-eslint's `no-wrapper-object-types`](https://typescript-eslint.io/rules/no-wrapper-object-types).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
function shout(text: String): Number {
  return text.length
}
```

##### ✅ Correct

```ts
function shout(text: string): number {
  return text.length
}
```

---

### `typescript/prefer-as-const`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require `as const` over asserting or annotating a literal with its own literal type.

#### Rule Details

`'get' as 'get'` and `let method: 'get' = 'get'` write the same literal twice, and the two copies can drift apart in an edit. `as const` says it once. This rule reports a string, number or boolean literal asserted or annotated with a literal type spelt exactly the same, on variables and class properties. The fix rewrites an assertion to `as const`; an annotation is reported without a fix, because removing it changes the declared type.

Reimplements [typescript-eslint's `prefer-as-const`](https://typescript-eslint.io/rules/prefer-as-const).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
const request = { method: 'get' as 'get' }
let mode: 'strict' = 'strict'
```

##### ✅ Correct

```ts
const request = { method: 'get' as const }
let mode = 'strict' as const
let level: 'low' | 'high' = 'low'
```

#### Limitations

The literal and its type are compared as written, so `'get' as "get"` is not reported. The original offers a suggestion for the annotation case; this rule reports without one.

---

### `typescript/prefer-namespace-keyword`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Require `namespace` rather than `module` to declare a TypeScript namespace.

#### Rule Details

`module Name {}` is the old spelling of a namespace, and it reads as though it declared an ES module. This rule reports a namespace declared with the `module` keyword and an identifier name, dotted names included. An ambient module named by a string, such as `declare module 'pkg' {}`, is a different construct and passes. The fix replaces the keyword with `namespace`.

Reimplements [typescript-eslint's `prefer-namespace-keyword`](https://typescript-eslint.io/rules/prefer-namespace-keyword).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
declare module Shapes {
  const sides: number
}
```

##### ✅ Correct

```ts
declare namespace Shapes {
  const sides: number
}

declare module 'shapes' {
  export const sides: number
}
```

---

### `typescript/triple-slash-reference`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>CODE_RULES</code></span></p>

Forbid `/// <reference path>` directives, and `/// <reference types>` directives for a module the file also imports.

#### Rule Details

A triple-slash reference pulls a file or a types package into the program from a comment, where an `import` would state the dependency in code. This rule reads the reference directives before the first statement. It reports every `path=` reference, and a `types=` reference whenever the same module is also imported with an `import` declaration or `import x = require()`, once per such import. A `lib=` reference passes, since nothing can import a built-in library declaration. It does not fix.

Reimplements [typescript-eslint's `triple-slash-reference`](https://typescript-eslint.io/rules/triple-slash-reference).

#### Options

This rule has no options. The [original's options](https://typescript-eslint.io/rules/triple-slash-reference/#options), which set the policy for each kind of reference, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
/// <reference path="./globals.d.ts" />
/// <reference types="node" />
import { readFileSync } from 'node'
```

##### ✅ Correct

```ts
/// <reference lib="dom" />
/// <reference types="vite/client" />
import { readFileSync } from 'node:fs'
```

## JSDoc rules

Reimplemented from [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc). [`JSDOC_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-JSDOC_RULES) turns on the ones its `recommended` configuration does.

| Rule | Reads | 🔧 | `JSDOC_RULES` |
| ---- | ----- | :-: | :-: |
| [`jsdoc/check-access`](#jsdoccheck-access) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/check-param-names`](#jsdoccheck-param-names) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/check-property-names`](#jsdoccheck-property-names) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/check-tag-names`](#jsdoccheck-tag-names) | TypeScript, JavaScript | 🔧 | ✅ |
| [`jsdoc/check-types`](#jsdoccheck-types) | TypeScript, JavaScript | 🔧 | ✅ |
| [`jsdoc/check-values`](#jsdoccheck-values) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/empty-tags`](#jsdocempty-tags) | TypeScript, JavaScript | 🔧 | ✅ |
| [`jsdoc/escape-inline-tags`](#jsdocescape-inline-tags) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/implements-on-classes`](#jsdocimplements-on-classes) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/informative-docs`](#jsdocinformative-docs) | TypeScript, JavaScript |  |  |
| [`jsdoc/no-defaults`](#jsdocno-defaults) | TypeScript, JavaScript | 🔧 | ✅ |
| [`jsdoc/no-types`](#jsdocno-types) | TypeScript, JavaScript | 🔧 | ✅ |
| [`jsdoc/reject-any-type`](#jsdocreject-any-type) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/reject-function-type`](#jsdocreject-function-type) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-description`](#jsdocrequire-description) | TypeScript, JavaScript |  |  |
| [`jsdoc/require-jsdoc`](#jsdocrequire-jsdoc) | TypeScript, JavaScript | 🔧 | ✅ |
| [`jsdoc/require-next-type`](#jsdocrequire-next-type) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-param`](#jsdocrequire-param) | TypeScript, JavaScript | 🔧 | ✅ |
| [`jsdoc/require-param-description`](#jsdocrequire-param-description) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-param-name`](#jsdocrequire-param-name) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-property`](#jsdocrequire-property) | TypeScript, JavaScript | 🔧 | ✅ |
| [`jsdoc/require-property-description`](#jsdocrequire-property-description) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-property-name`](#jsdocrequire-property-name) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-returns`](#jsdocrequire-returns) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-returns-check`](#jsdocrequire-returns-check) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-returns-description`](#jsdocrequire-returns-description) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-throws-type`](#jsdocrequire-throws-type) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-yields`](#jsdocrequire-yields) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-yields-check`](#jsdocrequire-yields-check) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/require-yields-type`](#jsdocrequire-yields-type) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/ts-no-empty-object-type`](#jsdocts-no-empty-object-type) | TypeScript, JavaScript |  | ✅ |
| [`jsdoc/valid-types`](#jsdocvalid-types) | TypeScript, JavaScript |  | ✅ |

---

### `jsdoc/check-access`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a JSDoc block's access control to name a valid level, once.

#### Rule Details

Access control in JSDoc is written either as `@access <level>` or as one of the shorthand tags `@package`, `@private`, `@protected` and `@public`. This rule reports an `@access` tag whose level is not one of package, private, protected or public, a block that combines `@access` with a shorthand tag, and a block carrying more than one access-control tag. Every JSDoc block in the file is read, whether or not it documents a declaration. It does not fix.

Reimplements [eslint-plugin-jsdoc's `check-access`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-access.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Clears the cache.
 *
 * @access internal
 */
export function clear(): void {
  return undefined
}

/**
 * Resets the store.
 *
 * @access private
 * @public
 */
export function reset(): void {
  return undefined
}
```

##### ✅ Correct

```ts
/**
 * Clears the cache.
 *
 * @access package
 */
export function clear(): void {
  return undefined
}
```

---

### `jsdoc/check-param-names`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require the `@param` tags of a function's JSDoc to name its parameters, in order.

#### Rule Details

A `@param` tag that names the wrong parameter documents something the function does not have, and it is the first thing to go stale after a rename. On functions, methods and method signatures, this rule reports a `@param` name that differs from the parameter at its position, a tag past the last parameter, and a duplicate tag. For a destructured parameter documented with no type or a plain object type, it also reports a property left out of the dotted `@param root.property` tags, a documented property the pattern does not have, and a dotted path whose root is not documented. A `this` parameter may be left undocumented. It stops at the first problem in a block and does not fix.

Reimplements [eslint-plugin-jsdoc's `check-param-names`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-param-names.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-param-names.md#options), which allow extra trailing tags, turn off the destructuring and missing-tag checks, choose which types skip property checks and enable a fixer, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Moves a point.
 *
 * @param x - The horizontal offset
 * @param z - The vertical offset
 */
export function move(x: number, y: number): void {
  return undefined
}

/**
 * Opens a connection.
 *
 * @param options - The settings
 * @param options.host - The host
 */
export function open({ host, port }: Settings): void {
  return undefined
}
```

##### ✅ Correct

```ts
/**
 * Opens a connection.
 *
 * @param options - The settings
 * @param options.host - The host
 * @param options.port - The port
 */
export function open({ host, port }: Settings): void {
  return undefined
}
```

---

### `jsdoc/check-property-names`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require each `@property` of a JSDoc block to be named once, with dotted paths after their root.

#### Rule Details

A `@property` tag documents a member of a `@typedef` or of a documented object. This rule reports a property name that appears twice for the same type definition, a block holding several `@typedef` tags being checked one definition at a time. When there are no duplicates, it reports a dotted path such as `@property options.port` whose root property is not documented. Every JSDoc block in the file is read. It does not fix.

Reimplements [eslint-plugin-jsdoc's `check-property-names`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-property-names.md).

#### Options

This rule has no options. The original's [`enableFixer`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-property-names.md#options) option, which removes duplicates, is not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * A server address.
 *
 * @typedef {object} Address
 * @property {string} host - The host
 * @property {string} host - The host name
 */

/**
 * A connection.
 *
 * @typedef {object} Connection
 * @property {number} options.port - The port
 */
```

##### ✅ Correct

```ts
/**
 * A connection.
 *
 * @typedef {object} Connection
 * @property {object} options - The settings
 * @property {number} options.port - The port
 */
```

---

### `jsdoc/check-tag-names`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require JSDoc block and inline tags to be known tags, written by their preferred names.

#### Rule Details

A misspelt or invented tag is silently ignored by documentation tools. This rule reports a block tag that JSDoc, TypeScript and TypeDoc do not know and the configuration does not define, and an inline tag other than `{@link}`, `{@linkcode}`, `{@linkplain}`, `{@tutorial}`, `{@inheritDoc}`, `{@label}`, `{@include}` and `{@includeCode}`. A synonym, such as `@return` or `@arg`, is reported and the fix renames it to the preferred tag, `@returns` or `@param`.

With the typed option on, tags that the type system makes redundant are reported too: `@type`, `@typedef`, `@property`, `@private` and similar tags everywhere, and tags such as `@function`, `@static` or `@memberof` outside ambient declarations (`declare` and the top level of `.d.ts` files), as well as an unnamed `@template`. The fix removes such a tag, or keeps its description and drops the type and, where the tag is always redundant, the tag name.

Reimplements [eslint-plugin-jsdoc's `check-tag-names`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-tag-names.md).

#### Options

| Option                                                                                                        | Type     | Default | Meaning                                       |
| ------------------------------------------------------------------------------------------------------------- | -------- | ------- | --------------------------------------------- |
| [`typed`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-tag-names.md#options)       | boolean  | false   | Report tags a type system makes redundant.    |
| [`definedTags`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-tag-names.md#options) | string[] | `[]`    | Extra block tag names to accept, without `@`. |

The original's options that turn the fixer off, accept JSX pragma tags and configure the inline tags are not read: fixes are always offered, JSX pragma tags are accepted only when defined, and the inline tag list is fixed.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Doubles a number.
 *
 * @arg value - The number
 * @return The double
 * @pure
 */
export function double(value: number): number {
  return value * 2
}
```

```ts
/**
 * A point.
 *
 * @typedef {object} Point
 */
export interface Point {
  x: number
}
```

##### ✅ Correct

```ts
/**
 * Doubles a number, see {@link triple}.
 *
 * @param value - The number
 * @returns The double
 * @pure
 */
export function double(value: number): number {
  return value * 2
}
```

#### Limitations

The original chooses its known tags by the [mode setting](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/settings.md#mode) and renames tags by the [tag name preference setting](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/settings.md#alias-preference). This rule reads neither: it accepts the union of the JSDoc, TypeScript and TypeDoc tags and applies the default preferences.

---

### `jsdoc/check-types`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require the types in JSDoc tags to spell native types the way TypeScript does.

#### Rule Details

A JSDoc type written `{String}` or `{regexp}` names a native type in the wrong case, and tools disagree on what it means. This rule reads the type of every typed tag, such as `@param`, `@returns` or `@type`, in every JSDoc block, and reports a name that spells `undefined`, `null`, `boolean`, `number`, `bigint`, `string`, `symbol`, `Array`, `Function`, `Date` or `RegExp` in another case, and `Object` where `object` is meant. The fix respells the names. It also reports `object` or `Object` given type arguments, such as `Object.<string, number>`, in favour of an index signature, without a fix.

Reimplements [eslint-plugin-jsdoc's `check-types`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-types.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-types.md#options), which exempt tag contexts, skip defaults and check parent and child types together, are not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Counts the words of a text.
 *
 * @param {String} text - The text
 * @returns {Object.<string, Number>} The counts
 */
export function count(text: string): Record<string, number> {
  return { [text]: 1 }
}
```

##### ✅ Correct

```ts
/**
 * Counts the words of a text.
 *
 * @param {string} text - The text
 * @returns {{[word: string]: number}} The counts
 */
export function count(text: string): Record<string, number> {
  return { [text]: 1 }
}
```

#### Limitations

The original picks preferred spellings by its mode setting and accepts a preferred types setting. This rule reads neither: the spellings are always those of TypeScript mode.

---

### `jsdoc/check-values`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require JSDoc tags that take a value to carry a valid one.

#### Rule Details

Several JSDoc tags are only useful with a well-formed value. In every JSDoc block, this rule reports a `@version` or `@since` that is missing or is not a semantic version, a `@kind` that is missing or is not one of JSDoc's kinds (class, constant, event, external, file, function, member, mixin, module, namespace, typedef), a `@license` that is missing or is not a valid SPDX expression, an empty `@author` or `@variation`, and an `@import` whose text is not an import declaration with a quoted module. It does not fix.

Reimplements [eslint-plugin-jsdoc's `check-values`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-values.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-values.md#options), which restrict authors and licenses, set a license pattern and require numeric variations, are not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * The cache.
 *
 * @since next
 * @license MIT-ish
 * @kind thing
 */
export const cache = new Map<string, string>()
```

##### ✅ Correct

```ts
/**
 * The cache.
 *
 * @since 1.2.0
 * @license MIT OR Apache-2.0
 * @kind constant
 */
export const cache = new Map<string, string>()
```

---

### `jsdoc/empty-tags`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require JSDoc marker tags, such as `@private` or `@readonly`, to carry no text.

#### Rule Details

Some tags only mark a symbol, and text after them is either ignored or misread as a name or type. In every JSDoc block, this rule reports one of `@abstract`, `@async`, `@generator`, `@global`, `@hideconstructor`, `@ignore`, `@inheritDoc`, `@inner`, `@instance`, `@internal`, `@overload`, `@override`, `@package`, `@private`, `@protected`, `@public`, `@readonly` and `@static` followed by a type, a name or a description. The fix clears the text after the tag on its line.

Reimplements [eslint-plugin-jsdoc's `empty-tags`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/empty-tags.md).

#### Options

This rule has no options. The original's [`tags`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/empty-tags.md#options) option, which adds tags to the list, is not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * The retry limit.
 *
 * @readonly always three
 */
export const limit = 3
```

##### ✅ Correct

```ts
/**
 * The retry limit, always three.
 *
 * @readonly
 */
export const limit = 3
```

---

### `jsdoc/escape-inline-tags`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Forbid an unescaped `@name` inside the text of a JSDoc block.

#### Rule Details

Documentation tools read an `@` followed by a word as the start of a tag, so `@scope` in the middle of a sentence can split the description or create a bogus tag. This rule reports an `@` that starts a word, at the start of a line or after whitespace, in a block's description and in the text of its tags, except inside `@example`. The message names the three ways to write it: as an inline tag `{@name}`, escaped as `\@name`, or in backticks. Names in the allowed list are left alone. It does not fix.

Reimplements [eslint-plugin-jsdoc's `escape-inline-tags`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/escape-inline-tags.md).

#### Options

| Option                                                                                                                 | Type     | Default | Meaning                                                           |
| ---------------------------------------------------------------------------------------------------------------------- | -------- | ------- | ----------------------------------------------------------------- |
| [`allowedInlineTags`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/escape-inline-tags.md#options) | string[] | `[]`    | Names, without `@`, that may appear unescaped, such as `"scope"`. |

The original's options that enable a fixer and choose its escaping style are not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Publishes the packages under @acme to the registry.
 */
export function publish(): void {
  return undefined
}
```

##### ✅ Correct

```ts
/**
 * Publishes the packages under `@acme` to the registry.
 */
export function publish(): void {
  return undefined
}
```

```ts
/**
 * Publishes the packages under @acme to the registry.
 */
export function publish(): void {
  return undefined
}
```

---

### `jsdoc/implements-on-classes`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Forbid `@implements` on a function that is not a class or constructor.

#### Rule Details

`@implements` says that a class fulfils an interface, so on a plain function it documents nothing true. This rule reports each `@implements` tag in the JSDoc block of a function, method or arrow function, unless the function is a class constructor or its block also carries `@class` or `@constructor`. Blocks on classes are not checked, since that is where the tag belongs. It does not fix.

Reimplements [eslint-plugin-jsdoc's `implements-on-classes`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/implements-on-classes.md).

#### Options

This rule has no options. The original's [`contexts`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/implements-on-classes.md#options) option, which adds node types to check, is not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Creates a logger.
 *
 * @implements {Logger}
 */
export function createLogger(): Logger {
  return console
}
```

##### ✅ Correct

```ts
/**
 * Writes to the console.
 *
 * @implements {Logger}
 */
export class ConsoleLogger implements Logger {
  log(message: string): void {
    console.log(message)
  }
}

/**
 * Creates a logger.
 *
 * @class
 * @implements {Logger}
 */
export function LegacyLogger(this: Logger): void {
  return undefined
}
```

---

### `jsdoc/informative-docs`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid JSDoc descriptions that only repeat the name of what they document.

#### Rule Details

"The user id" on a property called userId tells the reader nothing the code did not. This rule splits a block's description and each tag's description into words, camel case included, and removes the names of the documented declaration (and, for a class member, of its class), the tag's own name, and the filler words "a", "an", "i", "in", "of", "s" and "the", with "a" also covering "an" and "our". When no word is left, the description is reported. Empty descriptions pass; other rules require them. It does not fix.

Reimplements [eslint-plugin-jsdoc's `informative-docs`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/informative-docs.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/informative-docs.md#options), which set the aliases, the filler words and the tags to skip, are not read: the defaults apply.

#### Examples

##### ❌ Incorrect

```ts
/**
 * The user id.
 *
 * @param name - The name
 */
export function userId(name: string): string {
  return name
}
```

##### ✅ Correct

```ts
/**
 * Derives the identifier a user signs in with.
 *
 * @param name - The display name, lower-cased before use
 */
export function userId(name: string): string {
  return name
}
```

---

### `jsdoc/no-defaults`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Forbid default values in a function's JSDoc, where they belong in the signature.

#### Rule Details

A default written in the docs, as `@param [retries=3]` or `@default 3`, duplicates the default in the signature and drifts from it. On the JSDoc blocks of functions, this rule reports a `@param`, `@arg` or `@argument` whose bracketed name carries `=value`, and a `@default` or `@defaultvalue` tag with a value. The fix drops the value: the parameter keeps its brackets, `[retries]`, and the default tag is left bare.

Reimplements [eslint-plugin-jsdoc's `no-defaults`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-defaults.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-defaults.md#options), which add node types to check and also forbid the optional brackets, are not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Fetches a resource.
 *
 * @param url - The address
 * @param [retries=3] - How often to try again
 */
export function load(url: string, retries = 3): string {
  return url.repeat(retries)
}
```

##### ✅ Correct

```ts
/**
 * Fetches a resource.
 *
 * @param url - The address
 * @param [retries] - How often to try again
 */
export function load(url: string, retries = 3): string {
  return url.repeat(retries)
}
```

---

### `jsdoc/no-types`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Forbid types in the `@param` and `@returns` tags of TypeScript functions.

#### Rule Details

In TypeScript the signature already carries the types, so a type in braces in the JSDoc repeats it and can contradict it. This rule reports a type on a `@param`, `@arg`, `@argument`, `@returns` or `@return` tag in the JSDoc of a function, method or method signature, and a type on a `@property` or `@prop` tag in the JSDoc of a class. The fix removes the type and the space after the tag, across every line the type spans.

Reimplements [eslint-plugin-jsdoc's `no-types`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-types.md).

#### Options

This rule has no options. The original's [`contexts`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-types.md#options) option, which adds node types to check, is not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Adds two numbers.
 *
 * @param {number} a - The first
 * @param {number} b - The second
 * @returns {number} The sum
 */
export function add(a: number, b: number): number {
  return a + b
}
```

##### ✅ Correct

```ts
/**
 * Adds two numbers.
 *
 * @param a - The first
 * @param b - The second
 * @returns The sum
 */
export function add(a: number, b: number): number {
  return a + b
}
```

---

### `jsdoc/reject-any-type`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Forbid `any` and `*` in the types of JSDoc tags.

#### Rule Details

A JSDoc type of `{any}` or `{*}` says only that the value could be anything, which documents nothing. This rule reads the type of every typed tag in every JSDoc block and reports each `any` or `*` it contains, at any depth, such as `{Array<any>}`. It does not fix.

Reimplements [eslint-plugin-jsdoc's `reject-any-type`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/reject-any-type.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * The parsed payload.
 *
 * @type {Array<any>}
 */
export const payload = []
```

##### ✅ Correct

```ts
/**
 * The parsed payload.
 *
 * @type {Array<string>}
 */
export const payload = []
```

---

### `jsdoc/reject-function-type`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Forbid `Function` in the types of JSDoc tags.

#### Rule Details

`{Function}` accepts any callable and says nothing about its parameters or result. This rule reads the type of every typed tag in every JSDoc block and reports each `Function` it contains, at any depth, such as `{Array<Function>}`. A function type with its signature, `{(value: string) => void}`, passes. It does not fix.

Reimplements [eslint-plugin-jsdoc's `reject-function-type`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/reject-function-type.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * The registered listeners.
 *
 * @type {Array<Function>}
 */
export const listeners = []
```

##### ✅ Correct

```ts
/**
 * The registered listeners.
 *
 * @type {Array<(event: string) => void>}
 */
export const listeners = []
```

---

### `jsdoc/require-description`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require a function's JSDoc block to open with a plain description.

#### Rule Details

The description is what a reader and an editor tooltip show first, so a block made of tags alone leaves the function unexplained. This rule reports the JSDoc block of a function, method, getter, setter or constructor that has no description before its tags. When the text sits in a `@desc` or `@description` tag instead, the message says to drop the tag or add text above it. A block tagged `@ignore`, `@override`, `@implements` or `@inheritDoc`, or a member of a class whose block carries one of the first three, is exempt. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-description`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-description.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-description.md#options), which choose the description style, add node types to check, exempt more tags and skip constructors, getters or setters, are not read: plain descriptions are required on every kind of function.

#### Examples

##### ❌ Incorrect

```ts
/**
 * @param path - Where the file is
 * @returns Its contents
 */
export function read(path: string): string {
  return path
}
```

##### ✅ Correct

```ts
/**
 * Reads a text file.
 *
 * @param path - Where the file is
 * @returns Its contents
 */
export function read(path: string): string {
  return path
}
```

---

### `jsdoc/require-jsdoc`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a JSDoc block on function declarations and on the declarations the options name.

#### Rule Details

A missing block leaves a declaration without the description and tags that other JSDoc rules check and that editors show. This rule reports every function declaration that has no JSDoc block, and every declaration in a context the options list. A block on the first overload signature documents the implementation and the other overloads. Constructors, getters and setters are checked unless the options turn them off. The fix inserts an empty block before the declaration, or before its first decorator, at the declaration's indentation. A declaration that two listed contexts both match is reported twice, but fixed once.

Reimplements [eslint-plugin-jsdoc's `require-jsdoc`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-jsdoc.md).

#### Options

| Option                                                                                                                  | Type                     | Default | Meaning                                                                    |
| ----------------------------------------------------------------------------------------------------------------------- | ------------------------ | ------- | -------------------------------------------------------------------------- |
| [`contexts`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-jsdoc.md#options)                | context name[]           | `[]`    | Further declarations that need a block, from the list below.               |
| [`checkConstructors`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-jsdoc.md#options)       | boolean                  | true    | Check constructors.                                                        |
| [`exemptEmptyConstructors`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-jsdoc.md#options) | boolean                  | false   | Let a constructor go when it has no parameters and returns no value.       |
| [`checkGetters`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-jsdoc.md#options)            | boolean                  | true    | Check getters.                                                             |
| [`checkSetters`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-jsdoc.md#options)            | boolean \| `'no-getter'` | true    | Check setters, or with `'no-getter'` only those without a matching getter. |

The context names are `'exported-function'`, `'exported-default-function'`, `'exported-class'`, `'exported-default-class'`, `'exported-arrow-variable'` and `'exported-function-variable'` (a function assigned to an exported `const`), `'interface'`, `'type-alias'`, `'property-signature'`, `'method-signature'`, `'public-method'` (excluding an implementation that follows an overload signature), `'public-method-signature'`, `'public-property'`, `'public-abstract-method'` and `'public-abstract-property'`. A member is public unless it carries the private modifier or has a `#private` name.

The original's contexts are AST selectors and its `require` map chooses node types; this rule takes the named contexts above instead and always checks function declarations. The original's options for public-only checks, minimum line counts, empty functions and a custom fixer are not read, and its empty-constructor exemption defaults to on where this one defaults to off.

#### Examples

##### ❌ Incorrect

```ts
function parse(text: string): number {
  return Number(text)
}
```

```ts
export interface Point {
  x: number
}
```

##### ✅ Correct

```ts
/**
 * Reads a number from text.
 *
 * @param text - The digits
 * @returns The number
 */
function parse(text: string): number {
  return Number(text)
}

export const double = (value: number): number => value * 2
```

---

### `jsdoc/require-next-type`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a type on every `@next` tag.

#### Rule Details

The `@next` tag documents the values a caller sends into a generator through `next()`, and without a type it says nothing about them. This rule reports each JSDoc block in the file that holds a `@next` tag written without a type in braces, once per block. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-next-type`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-next-type.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Accumulates the numbers sent in.
 *
 * @next The number to add
 */
export function* total(): Generator<number, void, number> {
  let sum = 0
  while (true) sum += yield sum
}
```

##### ✅ Correct

```ts
/**
 * Accumulates the numbers sent in.
 *
 * @next {number} The number to add
 */
export function* total(): Generator<number, void, number> {
  let sum = 0
  while (true) sum += yield sum
}
```

---

### `jsdoc/require-param`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a `@param` tag for every parameter of a documented function.

#### Rule Details

A JSDoc block that documents some parameters and skips others leaves the reader guessing about the rest. On functions, methods and constructors that have a JSDoc block, this rule reports each parameter without a `@param` tag. A destructured parameter needs a tag for its root and one for each property, as `@param options.port`; an unnamed root is called root0, root1 and so on, unless a tag at its position already names it. A property under a documented path whose type is neither absent nor a plain object is not required. A `this` parameter is never required.

Getters and setters are not checked, and neither is a block tagged `@type`, `@ignore`, `@override`, `@implements` or `@inheritDoc`, or a member of a class whose block carries one of the middle three. The fix inserts the missing tags in parameter order, before the tag of the next documented parameter or after the last `@param`, typed `{...any}` for a rest parameter. A function without a JSDoc block is left to [`require-jsdoc`](#jsdocrequire-jsdoc).

Reimplements [eslint-plugin-jsdoc's `require-param`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param.md#options), which control the destructuring checks, the checked member kinds, the unnamed root name, the exempting tags, the node types checked and the fixers, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Connects to a server.
 *
 * @param host - The host name
 */
export function connect(host: string, { port, secure }: Options): void {
  return undefined
}
```

##### ✅ Correct

```ts
/**
 * Connects to a server.
 *
 * @param host - The host name
 * @param root0 - The connection settings
 * @param root0.port - The port
 * @param root0.secure - Whether to use TLS
 */
export function connect(host: string, { port, secure }: Options): void {
  return undefined
}
```

---

### `jsdoc/require-param-description`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require every `@param` tag in a function's JSDoc to have a description.

#### Rule Details

A `@param` tag that gives only a name tells the reader nothing the signature did not. On the JSDoc blocks of functions and methods, this rule reports each `@param` tag whose description is empty. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-param-description`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param-description.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param-description.md#options), which add node types to check and set a default description for destructured roots, are not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Resizes an image.
 *
 * @param width
 */
export function resize(width: number): number {
  return width
}
```

##### ✅ Correct

```ts
/**
 * Resizes an image.
 *
 * @param width - The new width in pixels
 */
export function resize(width: number): number {
  return width
}
```

---

### `jsdoc/require-param-name`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require every `@param` tag in a function's JSDoc to name its parameter.

#### Rule Details

A `@param` tag without a name cannot be matched to a parameter, so tools drop it or attach it to the wrong one. On the JSDoc blocks of functions and methods, this rule reports each `@param` tag that has no name, whether the tag is bare or carries only a type such as `@param {string}`. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-param-name`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param-name.md).

#### Options

This rule has no options. The original's [`contexts`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param-name.md#options) option, which adds node types to check, is not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Greets someone.
 *
 * @param {string}
 */
export function greet(name: string): string {
  return name
}
```

##### ✅ Correct

```ts
/**
 * Greets someone.
 *
 * @param {string} name - Who to greet
 */
export function greet(name: string): string {
  return name
}
```

---

### `jsdoc/require-property`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a `@typedef` or `@namespace` of a plain object type to list its properties.

#### Rule Details

A `@typedef {object}` without `@property` tags declares an object type and says nothing about its shape. In every JSDoc block of the file, this rule reports a `@typedef` or `@namespace` whose type is `object`, `Object` or PlainObject when the block holds no `@property` tag. The fix adds an empty `@property` line after the block's last tag, to be filled in.

Reimplements [eslint-plugin-jsdoc's `require-property`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-property.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * A server address.
 *
 * @typedef {object} Address
 */
```

##### ✅ Correct

```ts
/**
 * A server address.
 *
 * @typedef {object} Address
 * @property {string} host - The host name
 * @property {number} port - The port
 */

/**
 * A port number.
 *
 * @typedef {number} Port
 */
```

---

### `jsdoc/require-property-description`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require every `@property` tag to have a description.

#### Rule Details

A `@property` tag that gives only a name and type documents the shape but not the meaning of the property. In every JSDoc block of the file, this rule reports each `@property` tag whose description is empty. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-property-description`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-property-description.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * A server address.
 *
 * @typedef {object} Address
 * @property {string} host
 */
```

##### ✅ Correct

```ts
/**
 * A server address.
 *
 * @typedef {object} Address
 * @property {string} host - The host name, without a port
 */
```

---

### `jsdoc/require-property-name`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require every `@property` tag to name its property.

#### Rule Details

A `@property` tag without a name cannot be matched to a member, so documentation tools drop it. In every JSDoc block of the file, this rule reports each `@property` tag that has no name, whether it is bare or carries only a type such as `@property {string}`. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-property-name`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-property-name.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * A server address.
 *
 * @typedef {object} Address
 * @property {string}
 */
```

##### ✅ Correct

```ts
/**
 * A server address.
 *
 * @typedef {object} Address
 * @property {string} host - The host name
 */
```

---

### `jsdoc/require-returns`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a `@returns` tag, once, in the JSDoc of a function that returns a value.

#### Rule Details

When a documented function gives back a value, the reader needs to know what it is. On functions and methods that have a JSDoc block, this rule reports a block with no `@returns` tag when the function returns a value on some path, or has an expression body, or, for a declared signature, names a return type other than `void`, `undefined` or `never`. A returned `new Promise` counts only when its executor resolves a value. It also reports a block with more than one `@returns` tag. Constructors are skipped, and so are blocks tagged `@abstract`, `@virtual`, `@class`, `@constructor`, `@type`, `@interface`, `@ignore`, `@override`, `@implements` or `@inheritDoc`, and members of a class whose block carries one of `@ignore`, `@override` or `@implements`. Getters and setters are checked. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-returns`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns.md#options), which force the tag on async functions, check constructors or skip getters, add node types and exempt more tags, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Reads the setting.
 *
 * @param key - The setting's name
 */
export function read(key: string): string {
  return key
}
```

##### ✅ Correct

```ts
/**
 * Reads the setting.
 *
 * @param key - The setting's name
 * @returns Its value
 */
export function read(key: string): string {
  return key
}
```

---

### `jsdoc/require-returns-check`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a function documented with `@returns` to return a value.

#### Rule Details

A `@returns` tag promises callers a value, so a function that returns nothing contradicts its docs. On documented functions and methods, this rule reports a block with more than one `@returns` tag. With a single tag it reports the block when the function never returns a value, for an untyped tag, or when some path returns without a value, for a typed one. A type that admits `undefined` or `void`, such as `{string | undefined}`, an assertion type such as `{asserts value}`, and generator functions are exempt. A `{never}` tag is reported when the function does return a value. Async functions are skipped, since their value is the promise's, and so are constructors, blocks marked `@abstract`, `@virtual`, `@class`, `@constructor` or `@interface`, and members of a class documented as an `@interface`. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-returns-check`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns-check.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns-check.md#options), which stop exempting async functions and generators and report a missing return for undefined types, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Logs a message.
 *
 * @param message - What to log
 * @returns The message
 */
export function log(message: string): void {
  console.log(message)
}
```

##### ✅ Correct

```ts
/**
 * Logs a message.
 *
 * @param message - What to log
 * @returns The message
 */
export function log(message: string): string {
  console.log(message)
  return message
}
```

---

### `jsdoc/require-returns-description`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require every `@returns` tag in a function's JSDoc to have a description.

#### Rule Details

A `@returns` tag with no description says that something comes back but not what it means. On the JSDoc blocks of functions and methods, this rule reports each `@returns` tag whose description is empty, unless its type says nothing comes back: `{void}`, `{undefined}`, `{Promise<void>}` or `{Promise<undefined>}`. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-returns-description`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns-description.md).

#### Options

This rule has no options. The original's [`contexts`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns-description.md#options) option, which adds node types to check, is not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Counts the items.
 *
 * @returns
 */
export function count(): number {
  return 0
}
```

##### ✅ Correct

```ts
/**
 * Counts the items.
 *
 * @returns How many items the list holds
 */
export function count(): number {
  return 0
}

/**
 * Clears the items.
 *
 * @returns {void}
 */
export function clear(): void {
  return undefined
}
```

---

### `jsdoc/require-throws-type`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a type on every `@throws` tag.

#### Rule Details

A caller deciding what to catch needs to know what is thrown, and a `@throws` tag without a type only says that something might be. This rule reports each JSDoc block in the file that holds a `@throws` or `@exception` tag written without a type in braces, once per block. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-throws-type`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-throws-type.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Parses a port number.
 *
 * @param text - The digits
 * @returns The port
 * @throws When the text is not a valid port
 */
export function port(text: string): number {
  return Number(text)
}
```

##### ✅ Correct

```ts
/**
 * Parses a port number.
 *
 * @param text - The digits
 * @returns The port
 * @throws {RangeError} When the text is not a valid port
 */
export function port(text: string): number {
  return Number(text)
}
```

---

### `jsdoc/require-yields`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a `@yields` tag, once, in the JSDoc of a generator that yields a value.

#### Rule Details

When a documented generator produces values, the reader needs to know what they are. On functions and methods that have a JSDoc block, this rule reports a block with no `@yields` tag when the function is a generator that yields a value, or when the block is marked `@generator`. It also reports a block with more than one `@yields` tag. Constructors are skipped, and so are blocks tagged `@abstract`, `@virtual`, `@class`, `@constructor`, `@type`, `@interface`, `@ignore`, `@override`, `@implements` or `@inheritDoc`, and members of a class whose block carries one of `@ignore`, `@override` or `@implements`. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-yields`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-yields.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-yields.md#options), which require `@next` tags, force the tag on generators that yield nothing, add node types and exempt more tags, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Counts upwards from zero.
 */
export function* count(): Generator<number> {
  for (let n = 0; ; n += 1) yield n
}
```

##### ✅ Correct

```ts
/**
 * Counts upwards from zero.
 *
 * @yields The next number
 */
export function* count(): Generator<number> {
  for (let n = 0; ; n += 1) yield n
}
```

---

### `jsdoc/require-yields-check`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a function documented with `@yields` to yield a value.

#### Rule Details

A `@yields` tag promises values to whoever iterates the generator, so a function that yields nothing contradicts its docs. On documented functions and methods, this rule reports a block with more than one `@yields` tag, and a block whose single `@yields` tag stands over a function that yields no value, unless the tag's type admits `undefined` or `void`. A `{never}` tag is reported when the function does yield a value. Constructors, blocks marked `@abstract`, `@virtual`, `@class`, `@constructor` or `@interface`, and members of a class documented as an `@interface` are skipped. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-yields-check`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-yields-check.md).

#### Options

This rule has no options. The [original's options](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-yields-check.md#options), which limit the check to generators, add node types and check `@next` tags as well, are not read.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Walks the list.
 *
 * @yields Each item
 */
export function* walk(items: string[]): Generator<string> {
  return items.length
}
```

##### ✅ Correct

```ts
/**
 * Walks the list.
 *
 * @yields Each item
 */
export function* walk(items: string[]): Generator<string> {
  yield* items
}
```

---

### `jsdoc/require-yields-type`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require a type on every `@yields` tag.

#### Rule Details

A `@yields` tag without a type says that a generator produces values but not what they are. This rule reports each JSDoc block in the file that holds a `@yields` or `@yield` tag written without a type in braces, once per block. It does not fix.

Reimplements [eslint-plugin-jsdoc's `require-yields-type`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-yields-type.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Counts upwards from zero.
 *
 * @yields The next number
 */
export function* count(): Generator<number> {
  for (let n = 0; ; n += 1) yield n
}
```

##### ✅ Correct

```ts
/**
 * Counts upwards from zero.
 *
 * @yields {number} The next number
 */
export function* count(): Generator<number> {
  for (let n = 0; ; n += 1) yield n
}
```

---

### `jsdoc/ts-no-empty-object-type`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Forbid the empty object type `{}` in the types of JSDoc tags.

#### Rule Details

The type `{}` admits every value except `null` and `undefined`, literals included, which is rarely what a block means: `object` says "any object" and `unknown` says "any value". This rule reads the type of every typed tag in every JSDoc block and reports each empty object type it contains, at any depth, such as `{Array<{}>}`. An object type with members passes. It does not fix.

Reimplements [eslint-plugin-jsdoc's `ts-no-empty-object-type`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/ts-no-empty-object-type.md), the JSDoc counterpart of [`typescript/no-empty-object-type`](#typescriptno-empty-object-type).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * The cached entries.
 *
 * @type {Array<{}>}
 */
export const entries = []
```

##### ✅ Correct

```ts
/**
 * The cached entries.
 *
 * @type {Array<{key: string}>}
 */
export const entries = []
```

---

### `jsdoc/valid-types`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>JSDOC_RULES</code></span></p>

Require the types, names and namepaths in JSDoc tags to be well formed and to sit on tags that take them.

#### Rule Details

A type that does not parse, or a name on a tag that takes none, is silently misread by documentation tools and editors. In every JSDoc block of the file, this rule reports, stopping at the first problem of each tag:

- a malformed bracketed name: unpaired brackets, an empty name, an empty default, or a default containing an unquoted `=`
- a name or a bracketed type on a tag that takes none, such as `@private {string}`
- a missing name, type, or either one where the tag needs it, such as `@fires` without an event name or `@type` without a type
- a type that does not parse as a TypeScript-flavoured JSDoc type, such as `{Array<string}`
- a namepath with a stray character on tags such as `@memberof`, `@module`, `@property` or `@template`, and a `@borrows` without an `as` target
- an inline tag such as `{@link}` with no content, in a description or a tag's text

Missing `@param` and `@property` names are left to [`jsdoc/require-param-name`](#jsdocrequire-param-name) and [`jsdoc/require-property-name`](#jsdocrequire-property-name). It does not fix.

Reimplements [eslint-plugin-jsdoc's `valid-types`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/valid-types.md).

#### Options

This rule has no options. The original's [`allowEmptyNamepaths`](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/valid-types.md#options) option is not read: empty namepaths are reported where a tag needs one.

#### Examples

##### ❌ Incorrect

```ts
/**
 * Lists the names.
 *
 * @param {Array<string} names - The names
 * @returns The joined names
 */
export function list(names: string[]): string {
  return names.join(', ')
}
```

```ts
/**
 * The default port.
 *
 * @private {number}
 */
export const port = 8080
```

```ts
/**
 * See {@link} for details.
 */
export const docs = true
```

##### ✅ Correct

```ts
/**
 * Lists the names, see {@link join}.
 *
 * @param {Array<string>} names - The names
 * @returns The joined names
 */
export function list(names: string[]): string {
  return names.join(', ')
}
```

#### Limitations

The original reads tags by its mode setting; this rule always reads them in TypeScript mode, so tag structures that only the closure or plain JSDoc modes allow are reported.

## React rules

Reimplemented from [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react). [`REACT_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-REACT_RULES) turns on the ones its `recommended` configuration does.

| Rule | Reads | 🔧 | `REACT_RULES` |
| ---- | ----- | :-: | :-: |
| [`react/display-name`](#reactdisplay-name) | TypeScript, JavaScript |  | ✅ |
| [`react/jsx-key`](#reactjsx-key) | TypeScript, JavaScript |  | ✅ |
| [`react/jsx-no-comment-textnodes`](#reactjsx-no-comment-textnodes) | TypeScript, JavaScript |  | ✅ |
| [`react/jsx-no-duplicate-props`](#reactjsx-no-duplicate-props) | TypeScript, JavaScript |  | ✅ |
| [`react/jsx-no-target-blank`](#reactjsx-no-target-blank) | TypeScript, JavaScript | 🔧 | ✅ |
| [`react/jsx-no-undef`](#reactjsx-no-undef) | TypeScript, JavaScript |  | ✅ |
| [`react/jsx-uses-react`](#reactjsx-uses-react) | TypeScript, JavaScript |  | ✅ |
| [`react/jsx-uses-vars`](#reactjsx-uses-vars) | TypeScript, JavaScript |  | ✅ |
| [`react/no-children-prop`](#reactno-children-prop) | TypeScript, JavaScript |  | ✅ |
| [`react/no-danger-with-children`](#reactno-danger-with-children) | TypeScript, JavaScript |  | ✅ |
| [`react/no-deprecated`](#reactno-deprecated) | TypeScript, JavaScript |  | ✅ |
| [`react/no-direct-mutation-state`](#reactno-direct-mutation-state) | TypeScript, JavaScript |  | ✅ |
| [`react/no-find-dom-node`](#reactno-find-dom-node) | TypeScript, JavaScript |  | ✅ |
| [`react/no-is-mounted`](#reactno-is-mounted) | TypeScript, JavaScript |  | ✅ |
| [`react/no-render-return-value`](#reactno-render-return-value) | TypeScript, JavaScript |  | ✅ |
| [`react/no-string-refs`](#reactno-string-refs) | TypeScript, JavaScript |  | ✅ |
| [`react/no-unescaped-entities`](#reactno-unescaped-entities) | TypeScript, JavaScript |  | ✅ |
| [`react/no-unknown-property`](#reactno-unknown-property) | TypeScript, JavaScript | 🔧 | ✅ |
| [`react/require-render-return`](#reactrequire-render-return) | TypeScript, JavaScript |  | ✅ |

---

### `react/display-name`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Require every React component to have a display name.

#### Rule Details

A component without a name shows as anonymous in React's developer tools and in error stacks. This rule finds components the way React sees them: class components, [`createReactClass`](https://legacy.reactjs.org/docs/react-without-es6.html) objects, and functions that return JSX or `null` from a position a component can take, including those wrapped in [`memo`](https://react.dev/reference/react/memo) or [`forwardRef`](https://react.dev/reference/react/forwardRef). A component counts as named when it is declared or assigned under a name, when its [`displayName`](https://legacy.reactjs.org/docs/react-component.html#displayname) is set, or when a factory object lists it. An anonymous default export and an anonymous function handed to [`memo`](https://react.dev/reference/react/memo) or [`forwardRef`](https://react.dev/reference/react/forwardRef) are reported. It does not fix.

The rule reads the shared settings. The pragma (`{ react: { pragma: 'Preact' } }`, or a `@jsx` comment in the file) names the object [`memo`](https://react.dev/reference/react/memo) and [`forwardRef`](https://react.dev/reference/react/forwardRef) are read from, and `{ componentWrapperFunctions: [...] }` adds wrapper functions, as names or as `{ property, object }` objects. With a React version (`{ react: { version: '16.12' } }`) of 0.14.10 and later 0.14, 15.7 and later 15, or 16.12 and newer, the default when no version is set, a wrapper call whose argument is itself a call, such as `memo(forwardRef(...))`, is not reported, because those versions name it from the inner component.

Reimplements [eslint-plugin-react's `display-name`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/display-name.md).

#### Options

This rule has no options. The [original's options](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/display-name.md#rule-options), which ignore names the transpiler infers and check legacy context objects, are not read: inferred names count, and context objects are not checked.

#### Examples

##### ❌ Incorrect

```tsx
import { forwardRef, memo } from 'react'

export const Card = memo(() => <div className="card" />)

export const Input = forwardRef<HTMLInputElement>((props, ref) => <input ref={ref} />)
```

##### ✅ Correct

```tsx
import { forwardRef, memo } from 'react'

export const Card = memo(function Card() {
  return <div className="card" />
})

const Input = forwardRef<HTMLInputElement>((props, ref) => <input ref={ref} />)
Input.displayName = 'Input'
```

---

### `react/jsx-key`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Require a [`key`](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) prop on JSX elements in arrays and iterator callbacks.

#### Rule Details

React tells list items apart by their [`key`](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key); without one it falls back to the index, which mixes up state and DOM nodes when the list is reordered. This rule reports a JSX element without a [`key`](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) attribute when it sits directly in an array literal, or when it is returned by the callback of a `.map()` call or the second argument of `Array.from()`. In a callback it follows an expression body, both branches of a conditional, the right side of a logical expression, and the returns of a block body through `if` statements. A key passed only through a spread does not count. Nothing inside a `Children.toArray()` call is checked, since it assigns keys itself; the pragma setting (`{ react: { pragma: 'Preact' } }`, or a `@jsx` comment) names the object [`Children`](https://react.dev/reference/react/Children) may be read from. It does not fix.

Reimplements [eslint-plugin-react's `jsx-key`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-key.md).

#### Options

This rule has no options. The [original's options](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-key.md#rule-options), which check fragment shorthands, require the key before a spread and warn on duplicate keys, are not read: shorthand fragments are not checked.

#### Examples

##### ❌ Incorrect

```tsx
const items = ['a', 'b'].map((label) => <li>{label}</li>)

const cells = [<td>1</td>, <td>2</td>]
```

##### ✅ Correct

```tsx
const items = ['a', 'b'].map((label) => <li key={label}>{label}</li>)

const cells = [<td key="one">1</td>, <td key="two">2</td>]
```

---

### `react/jsx-no-comment-textnodes`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid text in JSX children that looks like a comment.

#### Rule Details

Inside JSX children, `// note` and `/* note */` are not comments: they render as text on the page. This rule reports a JSX text node in which any line, leading whitespace aside, starts with `//` or `/*`. A comment in JSX belongs in braces, as `{/* note */}`. It does not fix.

Reimplements [eslint-plugin-react's `jsx-no-comment-textnodes`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-comment-textnodes.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
const banner = (
  <header>
    // shown only on the home page
    <h1>Welcome</h1>
  </header>
)
```

##### ✅ Correct

```tsx
const banner = (
  <header>
    {/* shown only on the home page */}
    <h1>Welcome</h1>
  </header>
)
```

---

### `react/jsx-no-duplicate-props`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid naming the same prop twice on one JSX element.

#### Rule Details

When a JSX element repeats an attribute, only the last value takes effect, so the earlier one is dead code and usually a merge or copy mistake. This rule reports every attribute after the first with the same name, compared case-sensitively. Spread attributes and namespaced attributes such as `xlink:href` are not compared. It does not fix.

Reimplements [eslint-plugin-react's `jsx-no-duplicate-props`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md).

#### Options

This rule has no options. The original's [`ignoreCase`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md#rule-options) option is not read: names that differ only in case are different props.

#### Examples

##### ❌ Incorrect

```tsx
const field = <input name="email" type="text" name="mail" />
```

##### ✅ Correct

```tsx
const field = <input name="email" type="text" />
```

---

### `react/jsx-no-target-blank`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid `target="_blank"` on external links without `rel="noreferrer"`.

#### Rule Details

A link that opens another site in a new tab hands that page a handle to the opening window in older browsers, which it can use to navigate the original tab elsewhere. `rel="noreferrer"`, which implies `rel="noopener"`, cuts the handle. This rule reports an `<a>` element whose last `target=` attribute may be `"_blank"`, as a literal in any case or as either branch of a conditional, when its `href=` is an external literal (one starting with a scheme such as `https:` or with `//`) or any expression, and its `rel=` does not include noreferrer in every value it may take.

The fix adds `rel="noreferrer"` after the last attribute, gives a bare rel attribute that value, or appends noreferrer to a literal value. It is withheld when a spread attribute after the target, or a spread with no rel attribute at all, could supply the value, and when the rel value is an expression.

Reimplements [eslint-plugin-react's `jsx-no-target-blank`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-target-blank.md).

#### Options

This rule has no options. The [original's options](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-target-blank.md#rule-options), which allow the referrer, skip dynamic links, warn on spreads and check forms, are not read: the behaviour is fixed to the original's defaults.

#### Examples

##### ❌ Incorrect

```tsx
const docs = (
  <a href="https://example.com/docs" target="_blank">
    Docs
  </a>
)
```

```tsx
const profile = (url: string) => (
  <a href={url} target="_blank" rel="noopener">
    Profile
  </a>
)
```

##### ✅ Correct

```tsx
const docs = (
  <a href="https://example.com/docs" target="_blank" rel="noreferrer">
    Docs
  </a>
)

const help = (
  <a href="/help" target="_blank">
    Help
  </a>
)
```

#### Limitations

Only the `<a>` element is checked: the original's link components setting, which adds custom link components and their address props, is not read.

---

### `react/jsx-no-undef`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid JSX elements whose component is not declared.

#### Rule Details

A JSX element names a variable, and an undeclared one fails only when the element renders, usually because an import is missing or misspelt. This rule reports a capitalised element name, or the root object of a member name such as `<Form.Field>`, that no scope from the element out to the module declares. Lower-case names are DOM elements and namespaced names such as `svg:rect` are left alone. In a module, a file with imports or exports, globals do not count; in a script they do. It does not fix.

Reimplements [eslint-plugin-react's `jsx-no-undef`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md).

#### Options

This rule has no options. The original's [`allowGlobals`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md#rule-options) option is not read: a module's elements never resolve to globals.

#### Examples

##### ❌ Incorrect

```tsx
import { Button } from './button'

export const toolbar = (
  <Toolbar>
    <Button />
  </Toolbar>
)
```

##### ✅ Correct

```tsx
import { Button } from './button'
import { Toolbar } from './toolbar'

export const toolbar = (
  <Toolbar>
    <Button />
  </Toolbar>
)
```

---

### `react/jsx-uses-react`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Mark the JSX pragma, and the fragment component, as used wherever JSX appears.

#### Rule Details

With the classic JSX transform, every element compiles to a call on the pragma, [`React.createElement`](https://react.dev/reference/react/createElement) by default, so an `import React from 'react'` that the code never names is still needed. This rule reports nothing itself: it marks the pragma variable as used at every JSX element, and the pragma and the fragment component at every `<>` fragment, so that [`typescript/no-unused-vars`](#typescriptno-unused-vars) does not report them. It only has an effect when that rule runs too.

The pragma comes from a `@jsx` comment in the file, then the settings (`{ react: { pragma: 'h' } }`), then [`React`](https://react.dev/reference/react). The fragment's name comes from the settings (`{ react: { fragment: 'Frag' } }`), then [`Fragment`](https://react.dev/reference/react/Fragment). With the automatic JSX runtime, React 17 and later, the import is not needed and this rule can stay off.

Reimplements [eslint-plugin-react's `jsx-uses-react`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md).

#### Options

This rule has no options.

#### Examples

##### ✅ Correct

```tsx
import React from 'react'

export const greeting = <p>Hello</p>
```

---

### `react/jsx-uses-vars`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Mark variables named as JSX elements as used.

#### Rule Details

A component referenced only as `<Button />` is a use of the variable Button, but a generic unused-variable check does not see JSX element names as references. This rule reports nothing itself: it marks the variable an element names as used, or the root object of a member name such as `<Form.Field>`, so that [`typescript/no-unused-vars`](#typescriptno-unused-vars) does not report it. Lower-case and namespaced names are DOM elements and mark nothing. It only has an effect when that rule runs too.

Reimplements [eslint-plugin-react's `jsx-uses-vars`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md).

#### Options

This rule has no options.

#### Examples

##### ✅ Correct

```tsx
import { Button } from './button'

export const toolbar = <Button />
```

---

### `react/no-children-prop`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid passing children through a [`children`](https://react.dev/learn/passing-props-to-a-component#passing-jsx-as-children) prop.

#### Rule Details

Children belong between an element's tags, or after the props argument of [`createElement`](https://react.dev/reference/react/createElement), where every reader expects them. This rule reports a [`children`](https://react.dev/learn/passing-props-to-a-component#passing-jsx-as-children) attribute on a JSX element, and a [`createElement`](https://react.dev/reference/react/createElement) call whose props object literal has a [`children`](https://react.dev/learn/passing-props-to-a-component#passing-jsx-as-children) key. The call counts when it is read off the pragma, as [`React.createElement`](https://react.dev/reference/react/createElement), or when a bare [`createElement`](https://react.dev/reference/react/createElement) was imported or destructured from it. The pragma comes from a `@jsx` comment in the file, then the settings (`{ react: { pragma: 'h' } }`), then [`React`](https://react.dev/reference/react). It does not fix.

Reimplements [eslint-plugin-react's `no-children-prop`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md).

#### Options

This rule has no options. The original's [`allowFunctions`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md#rule-options) option is not read: a function passed as the children prop is reported too.

#### Examples

##### ❌ Incorrect

```tsx
import { createElement } from 'react'

const note = <Note children="Saved" />
const card = createElement('div', { children: 'Saved' })
```

##### ✅ Correct

```tsx
import { createElement } from 'react'

const note = <Note>Saved</Note>
const card = createElement('div', {}, 'Saved')
```

---

### `react/no-danger-with-children`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid setting both children and [`dangerouslySetInnerHTML`](https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html) on one element.

#### Rule Details

[`dangerouslySetInnerHTML`](https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html) replaces an element's content, so children given alongside it are either lost or make React throw. This rule reports a JSX element that has the HTML prop and also has children, or a [`children`](https://react.dev/learn/passing-props-to-a-component#passing-jsx-as-children) prop; whitespace that only spans a line break does not count as a child. It also reports a `.createElement()` call whose props carry the HTML prop while children are passed as further arguments or as a prop. Props are followed through spread attributes and identifiers to the object literal a variable is initialised with. It does not fix.

Reimplements [eslint-plugin-react's `no-danger-with-children`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-danger-with-children.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
const html = { __html: '<b>Saved</b>' }

const note = <div dangerouslySetInnerHTML={html}>Saved</div>
```

##### ✅ Correct

```tsx
const html = { __html: '<b>Saved</b>' }

const note = <div dangerouslySetInnerHTML={html} />
const plain = <div>Saved</div>
```

#### Limitations

Any `.createElement()` call is checked, whatever object it is read from; a bare `createElement` call is not.

---

### `react/no-deprecated`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid React APIs that the configured React version deprecates.

#### Rule Details

Deprecated APIs warn at run time and disappear in a later major version. This rule reports a deprecated API when it is read as a member, such as [`ReactDOM.render`](https://react.dev/reference/react-dom/render), imported by name from `'react'`, `'react-dom'`, `'react-dom/server'` or `'react-addons-perf'`, or destructured from one of those modules' objects or `require` calls. It also reports the legacy lifecycle methods [`componentWillMount`](https://react.dev/reference/react/Component#unsafe_componentwillmount), [`componentWillReceiveProps`](https://react.dev/reference/react/Component#unsafe_componentwillreceiveprops) and [`componentWillUpdate`](https://react.dev/reference/react/Component#unsafe_componentwillupdate) on class components and [`createReactClass`](https://legacy.reactjs.org/docs/react-without-es6.html) objects, from React 16.9. The message names the version, the replacement and, where there is one, a page explaining the change. The list runs from React 0.12 to the React 18 root API changes. It does not fix.

The rule reads the React version from the settings (`{ react: { version: '17.0' } }`) and reports only what that version already deprecates; without a version, or with `'detect'`, it assumes the newest and reports everything. The pragma (`{ react: { pragma: 'Preact' } }`, or a `@jsx` comment in the file) is the object the core APIs are read from.

Reimplements [eslint-plugin-react's `no-deprecated`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
import { render } from 'react-dom'
import { Component } from 'react'

render(<App />, document.getElementById('root'))

export class Clock extends Component {
  componentWillMount() {
    this.setState({ now: Date.now() })
  }
}
```

##### ✅ Correct

```tsx
import { createRoot } from 'react-dom/client'
import { Component } from 'react'

createRoot(document.getElementById('root')!).render(<App />)

export class Clock extends Component {
  componentDidMount() {
    this.setState({ now: Date.now() })
  }
}
```

#### Limitations

The version is never detected from the installed package; a project on an older React must set it, or it sees reports for deprecations it has not reached.

---

### `react/no-direct-mutation-state`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid assigning to [`this.state`](https://react.dev/reference/react/Component#state) outside the constructor of a class component.

#### Rule Details

React only re-renders when state changes through [`setState`](https://react.dev/reference/react/Component#setstate); writing to [`this.state`](https://react.dev/reference/react/Component#state) directly leaves the screen stale and can be overwritten by the next update. In class components and [`createReactClass`](https://legacy.reactjs.org/docs/react-without-es6.html) objects, this rule reports an assignment to [`this.state`](https://react.dev/reference/react/Component#state) or to anything under it, and an increment or decrement of something under it. Inside the constructor, where state is set up, assignments pass, but those inside a callback passed to a call there are reported, since the callback runs later. It does not fix.

Reimplements [eslint-plugin-react's `no-direct-mutation-state`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
import { Component } from 'react'

export class Counter extends Component<object, { count: number }> {
  increment() {
    this.state.count += 1
  }
}
```

##### ✅ Correct

```tsx
import { Component } from 'react'

export class Counter extends Component<object, { count: number }> {
  constructor(props: object) {
    super(props)
    this.state = { count: 0 }
  }

  increment() {
    this.setState(({ count }) => ({ count: count + 1 }))
  }
}
```

---

### `react/no-find-dom-node`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid calls to [`findDOMNode`](https://react.dev/reference/react-dom/findDOMNode).

#### Rule Details

[`findDOMNode`](https://react.dev/reference/react-dom/findDOMNode) reaches through a component to its DOM node, which breaks the component's abstraction, does not work with function components, is deprecated in strict mode and was removed in React 19. A ref on the element is the replacement. This rule reports a call of a bare [`findDOMNode`](https://react.dev/reference/react-dom/findDOMNode) and of any member named [`findDOMNode`](https://react.dev/reference/react-dom/findDOMNode), such as `ReactDOM.findDOMNode(this)`. It does not fix.

Reimplements [eslint-plugin-react's `no-find-dom-node`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-find-dom-node.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
import { findDOMNode } from 'react-dom'

export function focus(component: React.Component) {
  ;(findDOMNode(component) as HTMLElement).focus()
}
```

##### ✅ Correct

```tsx
import { useRef } from 'react'

export function Field() {
  const input = useRef<HTMLInputElement>(null)
  return <input ref={input} onClick={() => input.current?.focus()} />
}
```

---

### `react/no-is-mounted`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid calls to `this.isMounted()`.

#### Rule Details

[`isMounted`](https://legacy.reactjs.org/blog/2015/12/16/ismounted-antipattern.html) is an anti-pattern: code that checks it usually hides a missing cleanup, such as a subscription or timer left running after unmount, and the method does not exist on ES6 class components. This rule reports a call of `this.isMounted()` inside an object property or a class method. It does not fix: cancel the pending work when the component unmounts instead.

Reimplements [eslint-plugin-react's `no-is-mounted`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
import createReactClass from 'create-react-class'

export const Clock = createReactClass({
  tick() {
    if (this.isMounted()) this.setState({ now: Date.now() })
  },
})
```

##### ✅ Correct

```tsx
import createReactClass from 'create-react-class'

export const Clock = createReactClass({
  componentWillUnmount() {
    clearInterval(this.timer)
  },
})
```

---

### `react/no-render-return-value`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid using the return value of [`ReactDOM.render`](https://react.dev/reference/react-dom/render).

#### Rule Details

The legacy [`ReactDOM.render`](https://react.dev/reference/react-dom/render) returns a reference to the root component instance, which future React versions do not provide and which is not ready during concurrent rendering; a ref callback is the supported way to reach it. This rule reports a [`render`](https://react.dev/reference/react-dom/render) call on the renderer object when its value is used: assigned, stored in a variable or object property, returned, or the body of an arrow function. It does not fix.

The renderer object depends on the React version in the settings (`{ react: { version: '0.14' } }`): [`ReactDOM`](https://react.dev/reference/react-dom) from 15 on and when no version is set, [`React`](https://react.dev/reference/react) or [`ReactDOM`](https://react.dev/reference/react-dom) in 0.14, and [`React`](https://react.dev/reference/react) in 0.13.

Reimplements [eslint-plugin-react's `no-render-return-value`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-render-return-value.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
import ReactDOM from 'react-dom'

const app = ReactDOM.render(<App />, document.getElementById('root'))
```

##### ✅ Correct

```tsx
import ReactDOM from 'react-dom'

ReactDOM.render(<App />, document.getElementById('root'))
```

---

### `react/no-string-refs`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid string refs.

#### Rule Details

String refs are a legacy API with known problems, such as attaching to the wrong owner, and React 19 removed them; [`useRef`](https://react.dev/reference/react/useRef), [`createRef`](https://react.dev/reference/react/createRef) or a ref callback replaces them. This rule reports a [`ref`](https://react.dev/learn/manipulating-the-dom-with-refs) attribute whose value is a string literal, quoted or in braces. For React versions before 18.3, set in the settings (`{ react: { version: '16.14' } }`), it also reports reading [`this.refs`](https://legacy.reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs) inside a class component or [`createReactClass`](https://legacy.reactjs.org/docs/react-without-es6.html) object; with a newer version, or none set, that read is not reported. It does not fix.

Reimplements [eslint-plugin-react's `no-string-refs`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md).

#### Options

This rule has no options. The original's [`noTemplateLiterals`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md#rule-options) option is not read: a template literal used as a ref is not reported.

#### Examples

##### ❌ Incorrect

```tsx
const field = <input ref="email" />
```

##### ✅ Correct

```tsx
import { useRef } from 'react'

export function Field() {
  const email = useRef<HTMLInputElement>(null)
  return <input ref={email} />
}
```

---

### `react/no-unescaped-entities`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid characters in JSX text that are easily mistaken for markup.

#### Rule Details

A stray `>`, `}`, `"` or `'` in JSX text is usually a typo for a closing tag, brace or attribute quote, and a reader cannot tell whether it is meant to render. This rule reports each occurrence of those four characters in JSX text, and the message lists the entities that escape it, such as `&gt;` or `&quot;`. Text inside braces, `{'>'}`, is a JavaScript string and passes. It does not fix.

Reimplements [eslint-plugin-react's `no-unescaped-entities`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unescaped-entities.md).

#### Options

This rule has no options. The original's [`forbid`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unescaped-entities.md#rule-options) option, which replaces the list of characters, is not read.

#### Examples

##### ❌ Incorrect

```tsx
const hint = <p>Don't close the tab, it's still "saving"</p>
```

##### ✅ Correct

```tsx
const hint = <p>Don&apos;t close the tab, it&apos;s still &ldquo;saving&rdquo;</p>
const quote = <p>{"Don't close the tab"}</p>
```

#### Limitations

The parser rejects a bare `>` or `}` in JSX text as a syntax error, as the TypeScript compiler does, so in practice the file fails to parse before this rule can report those two characters; only quotes reach it.

---

### `react/no-unknown-property`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Forbid attributes on DOM elements that React does not know.

#### Rule Details

React renders DOM attributes by its own names, [`className`](https://react.dev/reference/react-dom/components/common#common-props) rather than `class`, so an HTML spelling or a typo is dropped or triggers a warning at run time. On lower-case DOM elements, this rule reports an attribute React does not recognise. An HTML or SVG name React renames, such as `class`, `for` or `stroke-width`, and a known name written in the wrong case, such as [`onclick`](https://react.dev/learn/responding-to-events), are fixed to React's name. An attribute React allows only on certain tags, such as [`crossOrigin`](https://react.dev/reference/react-dom/components/common#common-props) outside media and link elements, is reported with the tags that take it. Data and ARIA attributes, components, member names, custom elements with a dash, elements with an `is` attribute, and the `<fbt>` and `<fbs>` tags are left alone.

The React version in the settings (`{ react: { version: '16.0' } }`) matters for two groups: [`allowTransparency`](https://legacy.reactjs.org/docs/dom-elements.html) is known only before 16.1, and pointer event handlers such as [`onPointerDown`](https://react.dev/reference/react-dom/components/common#pointerevent-handler) only from 16.4, which is the case when no version is set.

Reimplements [eslint-plugin-react's `no-unknown-property`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md).

#### Options

This rule has no options. The [original's options](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md#rule-options), which ignore chosen attributes and require lower-case data attributes, are not read.

#### Examples

##### ❌ Incorrect

```tsx
const label = <label class="field" for="email" onclick={focus} />
const icon = <svg stroke-width="2" foo="bar" />
```

##### ✅ Correct

```tsx
const label = <label className="field" htmlFor="email" onClick={focus} />
const icon = <svg strokeWidth="2" data-icon="check" aria-hidden="true" />
```

---

### `react/require-render-return`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Require the [`render`](https://react.dev/reference/react/Component#render) method of a class component to return something.

#### Rule Details

A [`render`](https://react.dev/reference/react/Component#render) method without a `return` renders nothing, which is almost always a forgotten keyword after a refactor. This rule reports a [`render`](https://react.dev/reference/react/Component#render) member whose value is a function with a block body and no `return` of its own; a `return` inside a nested function, such as a `.map()` callback, does not count. An arrow function with an expression body passes. Class components are classes that extend [`Component`](https://react.dev/reference/react/Component) or [`PureComponent`](https://react.dev/reference/react/PureComponent), bare or read off the pragma, and objects passed to the class factory, [`createReactClass`](https://legacy.reactjs.org/docs/react-without-es6.html) unless the settings name another (`{ react: { createClass: 'createClass' } }`). It does not fix.

Reimplements [eslint-plugin-react's `require-render-return`](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/require-render-return.md).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
import { Component } from 'react'

export class List extends Component<{ items: string[] }> {
  render() {
    ;<ul>
      {this.props.items.map((item) => {
        return <li key={item}>{item}</li>
      })}
    </ul>
  }
}
```

##### ✅ Correct

```tsx
import { Component } from 'react'

export class List extends Component<{ items: string[] }> {
  render() {
    return (
      <ul>
        {this.props.items.map((item) => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    )
  }
}
```

## React hooks rules

Reimplemented from [eslint-plugin-react-hooks](https://react.dev/reference/eslint-plugin-react-hooks). [`REACT_RULES`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-REACT_RULES) turns both on.

| Rule | Reads | 🔧 | `REACT_RULES` |
| ---- | ----- | :-: | :-: |
| [`react-hooks/exhaustive-deps`](#react-hooksexhaustive-deps) | TypeScript, JavaScript |  | ✅ |
| [`react-hooks/rules-of-hooks`](#react-hooksrules-of-hooks) | TypeScript, JavaScript |  | ✅ |

---

### `react-hooks/exhaustive-deps`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Require the dependency arrays of React effect, memo and callback hooks to list exactly the reactive values their callback reads.

#### Rule Details

A hook such as [`useEffect`](https://react.dev/reference/react/useEffect) reruns its callback only when a value in its dependency array changes. A value the callback reads but the array omits leaves the callback working with a stale copy; a value listed but not read reruns it for nothing. The rule checks the calls of [`useEffect`](https://react.dev/reference/react/useEffect), [`useLayoutEffect`](https://react.dev/reference/react/useLayoutEffect), [`useCallback`](https://react.dev/reference/react/useCallback), [`useMemo`](https://react.dev/reference/react/useMemo) and [`useImperativeHandle`](https://react.dev/reference/react/useImperativeHandle), bare or off the React namespace, and reports:

- a missing dependency: a prop, state value or other value from the component's render scope that the callback reads and the array omits;
- an unnecessary or duplicate dependency, such as an outer constant or a value listed twice;
- an array that is not an array literal, or a callback that is not an inline function or a function declared in the component, whose dependencies cannot be checked;
- a dependency that changes on every render, such as an object or function created in the component body;
- an effect callback that is `async`, a [`ref.current`](https://react.dev/reference/react/useRef#returns) read in an effect cleanup, and an assignment to an outer variable that is lost after each render;
- a state setter called by an effect with no dependency array, which loops, and a [`useMemo`](https://react.dev/reference/react/useMemo) or [`useCallback`](https://react.dev/reference/react/useCallback) with no array, which does nothing.

Values known to be stable, such as the setter returned by [`useState`](https://react.dev/reference/react/useState), the dispatch of [`useReducer`](https://react.dev/reference/react/useReducer) and a ref object from [`useRef`](https://react.dev/reference/react/useRef), need not be listed. The message names the array the rule would write. The rule does not fix.

Reimplements [eslint-plugin-react-hooks' `exhaustive-deps`](https://react.dev/reference/eslint-plugin-react-hooks/lints/exhaustive-deps).

#### Options

This rule has no options. The original's [`additionalHooks`](https://react.dev/reference/eslint-plugin-react-hooks/lints/exhaustive-deps#options) option is not read, so custom hooks are never checked, and neither are its experimental options.

#### Examples

##### ❌ Incorrect

```tsx
function Search({ query }: { query: string }) {
  const [results, setResults] = useState([])
  useEffect(() => {
    find(query).then(setResults)
  }, [])
  return <List items={results} />
}
```

##### ✅ Correct

```tsx
function Search({ query }: { query: string }) {
  const [results, setResults] = useState([])
  useEffect(() => {
    find(query).then(setResults)
  }, [query])
  return <List items={results} />
}
```

#### Limitations

The original offers suggestions that rewrite the dependency array; this rule names the array in its message instead.

---

### `react-hooks/rules-of-hooks`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--preset">Preset <code>REACT_RULES</code></span></p>

Require React hooks to be called unconditionally, at the top level of a component or a custom hook.

#### Rule Details

React matches hook calls to their state by call order, so every render must call the same hooks in the same order. A hook is a function whose name is "use", or starts with "use" followed by a capital letter or a digit, called bare or off a capitalised object (`React.useState(...)`). The rule follows the code paths of each function and reports a hook call that:

- runs only on some paths through a component or custom hook: inside a condition, after an early return, or behind `&&` and `?:`;
- may run more than once, in a loop;
- sits in an async component or hook;
- sits in a class method, in a function whose name is neither a component (capitalised) nor a hook, inside a callback nested in a component, or at the top level of the module.

A function passed to [`forwardRef`](https://react.dev/reference/react/forwardRef) or [`memo`](https://react.dev/reference/react/memo) counts as a component. React's `use()` may be called conditionally and in loops, and is only checked for where it is called. The rule does not fix.

Reimplements [eslint-plugin-react-hooks' `rules-of-hooks`](https://react.dev/reference/eslint-plugin-react-hooks/lints/rules-of-hooks).

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```tsx
function Profile({ id }: { id?: string }) {
  if (!id) return null
  const [user, setUser] = useState(null)
  return <p>{user}</p>
}

function load() {
  return useContext(Session)
}
```

##### ✅ Correct

```tsx
function Profile({ id }: { id?: string }) {
  const [user, setUser] = useState(null)
  if (!id) return null
  return <p>{user}</p>
}

function useSession() {
  return useContext(Session)
}
```

#### Limitations

The checks the original's newer releases make on functions returned by [`useEffectEvent`](https://react.dev/reference/react/useEffectEvent) are not made.

## package.json rules

Reimplemented from [eslint-plugin-package-json](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json). No preset turns it on; name it by id.

| Rule | Reads | 🔧 |
| ---- | ----- | :-: |
| [`package-json/restrict-dependency-ranges`](#package-jsonrestrict-dependency-ranges) | JSON |  |

---

### `package-json/restrict-dependency-ranges`

<p class="rule-facts"><span class="rule-fact">Reads JSON</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require the dependency versions of a `package.json` to use the range types the configuration allows.

#### Rule Details

Whether a project pins its dependencies, takes caret ranges or takes tilde ranges is a policy, and a manifest that mixes them updates some packages further than intended. The rule reads the [`dependencies`](https://docs.npmjs.com/cli/configuring-npm/package-json#dependencies), [`devDependencies`](https://docs.npmjs.com/cli/configuring-npm/package-json#devdependencies), [`peerDependencies`](https://docs.npmjs.com/cli/configuring-npm/package-json#peerdependencies) and [`optionalDependencies`](https://docs.npmjs.com/cli/configuring-npm/package-json#optionaldependencies) of a `package.json` and reports a version whose range type is not allowed for its section: a pin is an exact version such as `1.2.3`, a caret range starts with `^`, a tilde range with `~`. The `workspace:` protocol is understood, with `workspace:*` counted as a pin. A bare `*` is always reported. Versions the rule cannot read as a range, such as tags, URLs, `file:` or `npm:` aliases, are skipped. With no options the rule reports nothing.

Each report carries one suggestion per allowed range type that rewrites the version, such as `>=1.2.3` to `^1.2.3`. Suggestions appear in the JSON report and are never applied by `--fix`; the rule does not fix.

Reimplements [eslint-plugin-package-json's `restrict-dependency-ranges`](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/blob/main/docs/rules/restrict-dependency-ranges.md).

#### Options

The options are one restriction object, or an array of them. For each dependency the last restriction in the array whose sections include the dependency's section applies.

| Option                           | Type                   | Default      | Meaning                                                                  |
| -------------------------------- | ---------------------- | ------------ | ------------------------------------------------------------------------ |
| [`rangeType`](#package-jsonrestrict-dependency-ranges)          | `string` or `string[]` | required     | The allowed range type or types: `"pin"`, `"caret"` or `"tilde"`.        |
| [`forDependencyTypes`](#package-jsonrestrict-dependency-ranges) | `string[]`             | all sections | The sections the restriction applies to, such as `["peerDependencies"]`. |

The original's [`forPackages` and `forVersions`](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/blob/main/docs/rules/restrict-dependency-ranges.md#options) filters are not read.

#### Examples

##### ❌ Incorrect, with { "rangeType": "pin" }

```json
{
  "name": "example",
  "dependencies": { "react": "^19.0.0", "lodash": "*" }
}
```

##### ❌ Incorrect, with pinned dependencies and caret peers

```json
{
  "name": "example",
  "peerDependencies": { "react": "19.0.0" }
}
```

##### ✅ Correct, with { "rangeType": "pin" }

```json
{
  "name": "example",
  "dependencies": { "react": "19.0.0", "shared": "workspace:*" },
  "devDependencies": { "fixtures": "file:../fixtures" }
}
```

##### ✅ Correct, with pinned dependencies and caret peers

```json
{
  "name": "example",
  "dependencies": { "react": "19.0.0" },
  "peerDependencies": { "react": "^19.0.0" }
}
```

## Convention rules

The package's own rules, written for the hyperfrontend repository and general enough to ship. No preset turns them on; name each by id.

| Rule | Reads | 🔧 |
| ---- | ----- | :-: |
| [`assertive-test-names`](#assertive-test-names) | TypeScript, JavaScript |  |
| [`codeblock-line-width`](#codeblock-line-width) | Markdown |  |
| [`escape-package-tags`](#escape-package-tags) | TypeScript, JavaScript | 🔧 |
| [`export-order`](#export-order) | TypeScript, JavaScript | 🔧 |
| [`import-order`](#import-order) | TypeScript, JavaScript | 🔧 |
| [`jest-mock-after-imports`](#jest-mock-after-imports) | TypeScript, JavaScript | 🔧 |
| [`max-file-lines`](#max-file-lines) | TypeScript, JavaScript |  |
| [`max-path-occurrences`](#max-path-occurrences) | TypeScript, JavaScript |  |
| [`no-ascii-art-diagrams`](#no-ascii-art-diagrams) | Markdown |  |
| [`no-async-fs-api`](#no-async-fs-api) | TypeScript, JavaScript |  |
| [`no-decorative-header-comments`](#no-decorative-header-comments) | TypeScript, JavaScript | 🔧 |
| [`no-deprecated-tag`](#no-deprecated-tag) | TypeScript, JavaScript |  |
| [`no-enum`](#no-enum) | TypeScript, JavaScript |  |
| [`no-inline-type-literal`](#no-inline-type-literal) | TypeScript, JavaScript |  |
| [`no-manual-table-of-contents`](#no-manual-table-of-contents) | Markdown |  |
| [`no-mixed-type-export`](#no-mixed-type-export) | TypeScript, JavaScript | 🔧 |
| [`no-mixed-type-import`](#no-mixed-type-import) | TypeScript, JavaScript | 🔧 |
| [`no-namespace-import`](#no-namespace-import) | TypeScript, JavaScript |  |
| [`no-plain-inline-comments`](#no-plain-inline-comments) | TypeScript, JavaScript | 🔧 |
| [`no-section-dividers`](#no-section-dividers) | TypeScript, JavaScript | 🔧 |
| [`no-todo-comments`](#no-todo-comments) | TypeScript, JavaScript |  |
| [`no-unsafe-regex`](#no-unsafe-regex) | TypeScript, JavaScript |  |
| [`one-assertion-per-test`](#one-assertion-per-test) | TypeScript, JavaScript |  |
| [`prefer-exec-file-sync`](#prefer-exec-file-sync) | TypeScript, JavaScript |  |
| [`prefer-jsdoc-over-trailing-comments`](#prefer-jsdoc-over-trailing-comments) | TypeScript, JavaScript | 🔧 |
| [`readme-paragraph-length`](#readme-paragraph-length) | Markdown |  |
| [`require-codeblock-language`](#require-codeblock-language) | Markdown |  |
| [`require-node-protocol`](#require-node-protocol) | TypeScript, JavaScript | 🔧 |

---

### `assertive-test-names`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid the word "should" in test titles.

#### Rule Details

A test title states a fact: "returns null for empty input" is shorter and clearer than "should return null for empty input". The rule reports a title containing the word "should", in any letter case, on the test-declaring calls of Jest-style runners: [`it`](https://jestjs.io/docs/api#testname-fn-timeout), [`test`](https://jestjs.io/docs/api#testname-fn-timeout), [`fit`](https://jestjs.io/docs/api#testonlyname-fn-timeout), [`xit`](https://jestjs.io/docs/api#testskipname-fn) and [`xtest`](https://jestjs.io/docs/api#testskipname-fn). Modifier chains (`it.only(...)`, `test.skip(...)`, `test.todo(...)`, `it.failing(...)`, `it.concurrent(...)`) and table forms (`it.each(table)(...)`, ``it.each`table`(...)``) are checked too.

Suite titles passed to [`describe`](https://jestjs.io/docs/api#describename-fn) are left alone: they name units, not behaviours. Titles computed at run time, such as a template literal with substitutions, are not read. The rule does not fix.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
it('should return the correct value', () => {})

test('should throw an error when input is invalid', () => {})

test.only('should execute the focused test', () => {})

it.each([1, 2])('should handle %s', () => {})
```

##### ✅ Correct

```ts
it('returns the correct value', () => {})

test('throws an error when input is invalid', () => {})

it.each([1, 2])('handles %s', () => {})

describe('should-style prose is allowed in suite titles', () => {})
```

---

### `codeblock-line-width`

<p class="rule-facts"><span class="rule-fact">Reads Markdown</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Report documentation code lines that are wide only because they cram a list onto one line.

#### Rule Details

On a phone a code block shows about forty-five characters of a line, and the rest scrolls sideways. Scrolling is right for a line that has to be wide and wrong for one that only happens to be: an object literal with four members, a call with five arguments, a shell command with a run of flags. Those read better one entry per line on every screen. The rule is authoring feedback for that second kind of line, not a width limit, and it does not fix. It reports a line of a fenced code block in markdown when all three hold:

1. The line is wider than [`minLineLength`](#codeblock-line-width) and no wider than [`maxLineLength`](#codeblock-line-width), tabs counted as four columns.
2. Nothing about the line exempts it (see below).
3. The line has a shape vertical formatting would fix: in a shell block (bash, sh, zsh, PowerShell and the like), a command with two or more flags or six or more words; in any other block, a bracketed span that opens and closes on the line and holds three or more entries.

Strings and nested brackets are skipped when entries are counted, so a comma inside a string is not an entry and `f(a, g(b, c))` holds two entries, not three.

##### Lines the rule leaves alone

| Line                                                                    | Why                                       |
| ----------------------------------------------------------------------- | ----------------------------------------- |
| Contains a URL                                                          | A URL is one token and cannot be folded   |
| Contains a token of 32 or more characters with no space                 | A hash, a path, a key, a generated value  |
| Starts as a comment (`//`, `#`, `*`, `/*`, `

```ts
/**
 * End-to-end tests for @acme/versioning
 */

/**
 * Entry point for the \@acme/package plugin.
 */

/**
 * @acme/workspace - a plugin for generated reports.
 */
```

##### ✅ Correct, with { "prefixes": ["@acme"] }

```ts
/**
 * End-to-end tests for `@acme/versioning`
 */

/**
 * `@acme/workspace` - a plugin for generated reports.
 */

/**
 * The broker.
 *
 * @module @acme/nexus
 */
```

#### When Not To Use It

When a project deliberately writes package references as JSDoc tags.

---

### `export-order`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require re-exports to be listed type-only first, then grouped by where their source points.

#### Rule Details

The rule applies the grouping of [import-order](#import-order) to re-exports, the `export ... from` and `export * from` statements of an index file. The expected order, alphabetical by source within each group:

1. Type-only re-exports (`export type`), themselves ordered by the groups below
2. Node built-in modules, with the `node:` prefix or without it
3. External packages
4. Packages in the scopes listed in [`internalScopes`](#export-order), when any are configured
5. Parent-directory sources (`../`), the deepest first
6. Current-directory sources (`./`)

Exports of local declarations, such as `export const` or `export function`, are not ordered. The rule reports once, at the first re-export, when the re-exports are out of order. The fix rewrites them in the expected order, one per line, and is offered only when the re-exports form one unbroken run.

#### Options

| Option                       | Type       | Default | Meaning                                                                                                  |
| ---------------------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------- |
| [`internalScopes`](#export-order) | `string[]` | `[]`    | Package scopes, such as `"@acme"`, whose packages form a group of their own after the external packages. |

Without internal scopes, a scoped package is an external package like any other.

#### Examples

##### ❌ Incorrect

```ts
export { helper } from './helper'
export type { Config } from './types'
export { readFileSync } from 'node:fs'
export { default as express } from 'express'
```

##### ❌ Incorrect, with { "internalScopes": ["@acme"] }

```ts
export * from '@acme/utils'
export * from 'express'
```

##### ✅ Correct

```ts
export type { Config } from './types'
export { readFileSync } from 'node:fs'
export { default as express } from 'express'
export { helper } from './helper'
```

##### ✅ Correct, with { "internalScopes": ["@acme"] }

```ts
export type * from './types'
export * from 'express'
export * from '@acme/utils'
export * from './helper'
```

#### When Not To Use It

When another tool already owns the order of re-exports with its own convention.

---

### `import-order`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require imports to be listed type-only first, then grouped by where their source points.

#### Rule Details

A predictable import order makes a file's dependencies easy to scan and keeps merge conflicts in the import block small. The rule expects this order, alphabetical by source within each group:

1. Type-only imports (`import type`), themselves ordered by the groups below
2. Node built-in modules, with the `node:` prefix or without it (`fs/promises`)
3. External packages
4. Packages in the scopes listed in [`internalScopes`](#import-order), when any are configured
5. Parent-directory imports (`../`), the deepest first
6. Current-directory imports (`./`)

The rule reports once, at the first import, when the imports are out of that order. The fix rewrites them in the expected order, one per line, and is offered only when the imports form one unbroken run; with a statement between two imports it reports without a fix.

#### Options

| Option                       | Type       | Default | Meaning                                                                                                  |
| ---------------------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------- |
| [`internalScopes`](#import-order) | `string[]` | `[]`    | Package scopes, such as `"@acme"`, whose packages form a group of their own after the external packages. |

Without internal scopes, a scoped package is an external package like any other.

#### Examples

##### ❌ Incorrect

```ts
import { helper } from './helper'
import type { Config } from './types'
import { readFileSync } from 'node:fs'
import express from 'express'
```

##### ❌ Incorrect, with { "internalScopes": ["@acme"] }

```ts
import { someUtil } from '@acme/utils'
import express from 'express'
```

##### ✅ Correct

```ts
import type { Config } from './types'
import { readFileSync } from 'node:fs'
import express from 'express'
import { shared } from '../../shared'
import { core } from '../core'
import { helper } from './helper'
```

##### ✅ Correct, with { "internalScopes": ["@acme"] }

```ts
import { readFileSync } from 'node:fs'
import express from 'express'
import { someUtil } from '@acme/utils'
import { helper } from './helper'
```

#### When Not To Use It

When another tool, such as a formatter plugin, already owns import ordering with its own convention. The same grouping applies to re-exports in [export-order](#export-order).

---

### `jest-mock-after-imports`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require `jest.mock()` and `jest.unmock()` calls to come after every import statement.

#### Rule Details

Jest's transform hoists mock registrations above the imports, and the load hook of [`@hyperfrontend/testing`](https://www.hyperfrontend.dev/docs/libraries/testing.md) finds them wherever they sit, so placement does not change execution: the mocks register first either way. Writing them before the imports buys nothing and pushes the module's real dependencies below a wall of mock boilerplate. The rule reports each top-level `jest.mock()` or `jest.unmock()` call that comes before the last import.

The fix moves the imports above the mock calls, keeping each group's order. It is offered only when the imports and mocks form one unbroken run; with another statement among them the rule reports without a fix.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
jest.mock('./warn-handler', () => ({ createHandler: jest.fn() }))
jest.mock('@rollup/plugin-json', () => jest.fn(() => ({ name: 'json' })))

import type { BuildContext } from '../../models'
import { createConfig } from './config'
import { createHandler } from './warn-handler'
```

##### ✅ Correct

```ts
import type { BuildContext } from '../../models'
import { createConfig } from './config'
import { createHandler } from './warn-handler'

jest.mock('./warn-handler', () => ({ createHandler: jest.fn() }))
jest.mock('@rollup/plugin-json', () => jest.fn(() => ({ name: 'json' })))
```

#### Limitations

Only calls on an object named jest, written as top-level statements, are read; a mock registered through another name or inside a block is not seen.

---

### `max-file-lines`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Limit the line count of files that hold more than one function.

#### Rule Details

A long file with many functions usually carries more than one responsibility, and splitting it gives smaller modules that are easier to read, test and review. The rule counts the functions in a file (declarations, function expressions, arrow functions and class methods, inline callbacks included) and, when there are two or more, reports a file longer than its budget. A file with one function or none may be as long as it needs. The rule does not fix.

Test files, whose names end in `.spec` or `.test` followed by `.ts`, `.tsx`, `.js` or `.jsx`, have their own, higher budget.

#### Options

| Option                     | Type     | Default | Meaning                                         |
| -------------------------- | -------- | ------- | ----------------------------------------------- |
| [`maxLines`](#max-file-lines)     | `number` | `300`   | The most lines an implementation file may hold. |
| [`maxLinesTest`](#max-file-lines) | `number` | `500`   | The most lines a test file may hold.            |

#### Examples

##### ❌ Incorrect, with { "maxLines": 4 }

```ts
export function parse(input: string): string[] {
  return input.split(',')
}

export function validate(items: string[]): boolean {
  return items.every((item) => item.length > 0)
}
```

##### ✅ Correct, with { "maxLines": 4 }, one function of any length

```ts
export function parse(input: string): string[] {
  const items = input.split(',')
  const kept = items.filter(Boolean)
  return kept
}
```

#### When Not To Use It

For generated files, or for files that are comprehensive by design, such as a module of type definitions. A per-file override is usually better than turning the rule off. Unlike [ESLint's `max-lines`](https://eslint.org/docs/latest/rules/max-lines), this rule exempts single-function files.

#### Limitations

Lines are counted by line starts, so a file that ends with a newline counts the empty line after it: a 300-line file with a final newline counts as 301.

---

### `max-path-occurrences`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Allow at most one type import and one value import per module path, and in an index file one type re-export and one value re-export per path.

#### Rule Details

Imports from the same module scattered over several statements are noise that belongs in one statement. The rule groups a file's import statements by source and kind, `import type` apart from value imports, and reports every statement of a group that holds more than one. The pattern it leaves room for is one type import and one value import per path.

Re-exports (`export ... from` and `export * from`) are grouped the same way, but only in index files (`index.ts`, `index.tsx`, `index.js`, `index.jsx`), where they make up the public surface. Other files may re-export from one path as often as they like. The rule does not fix.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
import { foo } from './module'
import { bar } from './module'
```

```ts
import type { User } from './types'
import type { Config } from './types'
```

##### ✅ Correct

```ts
import type { User, Config } from './types'
import { createUser } from './types'
```

Re-exports outside an index file are not counted:

```ts
export { foo } from './module'
export { bar } from './module'
```

#### Limitations

An inline type specifier (`import { type User } from './types'`) makes a value import, so it shares a group with the other value imports from the path. Pair the rule with [no-mixed-type-import](#no-mixed-type-import) to keep the two kinds apart.

---

### `no-ascii-art-diagrams`

<p class="rule-facts"><span class="rule-fact">Reads Markdown</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid diagrams drawn with box characters in markdown code blocks; prefer Mermaid.

#### Rule Details

A diagram drawn in box characters is hard to edit, unreadable to a screen reader, and breaks at any width or font other than the author's. A Mermaid diagram is source a reader can change and a renderer can lay out. The rule reports a fenced code block whose lines draw a box: at least three lines carrying two or more box characters (`┌ ┐ └ ┘ │ ─ ├ ┤ ┬ ┴ ┼`, their double-line forms, `+` and `|`), with an opening corner, a right-hand border character, and at least two lines with a vertical border. The rule does not fix.

A directory tree drawn with `├──` and `└──` is not a box and is left alone, as are markdown tables outside code blocks. In a file named `README.md` the message points at a separate architecture document instead, since npm does not render Mermaid.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

````markdown
The pipeline:

```
┌──────────────────────────────────────┐
│               PIPELINE               │
├──────────────────────────────────────┤
│  Input ──▶ │ Process │ ──▶ │ Output  │
└──────────────────────────────────────┘
```
````

##### ✅ Correct

````markdown
The pipeline:

```mermaid
flowchart LR
    A[Input] --> B[Process]
    B --> C[Output]
```
````

##### ✅ Correct, a directory tree

````markdown
The project layout:

```
src/
├── index.ts
├── utils/
│   └── helper.ts
└── types.ts
```
````

#### Limitations

Only fences of backticks are read; a block fenced with tildes is not checked.

---

### `no-async-fs-api`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid the asynchronous Node file system APIs in favour of their synchronous twins.

#### Rule Details

In scripts, build tools and command-line programs, synchronous file access is simpler to read and to order: each operation finishes before the next line runs, and errors arrive as ordinary exceptions. The rule reports:

- an import or `require()` of `fs/promises` or `node:fs/promises`;
- a named import from `fs` or `node:fs` of a method that has a synchronous twin, such as [`readFile`](https://nodejs.org/api/fs.html#fsreadfilepath-options-callback) (use [`readFileSync`](https://nodejs.org/api/fs.html#fsreadfilesyncpath-options));
- such a method read through a namespace or default import of `fs`, such as `fs.readFile(...)`.

The set of methods is read from the running Node's own `fs` module: every method that has a twin of the same name ending in Sync. The rule does not fix.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
import { readFile } from 'node:fs/promises'

const content = await readFile('file.txt', 'utf-8')
```

```ts
import * as fs from 'node:fs'

fs.readFile('file.txt', (error, data) => {})
```

##### ✅ Correct

```ts
import { readFileSync, writeFileSync } from 'node:fs'

const content = readFileSync('file.txt', 'utf-8')
writeFileSync('output.txt', content)
```

#### When Not To Use It

In servers and other long-running processes, where blocking I/O stalls the event loop, and wherever many files are processed concurrently.

#### Limitations

The promise API reached as a property, `fs.promises.readFile(...)`, and methods called on an inline `require('fs')` are not reported.

---

### `no-decorative-header-comments`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid a file from opening with a block comment of prose alone that documents nothing.

#### Rule Details

A header such as "File: utils.ts, Description: utility functions" repeats what the file name and the code already say, and goes stale. The rule reads the first comment of a file, when nothing but whitespace precedes it, and reports it when it is a block comment of two or more lines that:

- carries no tag (no line opens with `@`, so `@module`, `@packageDocumentation` and tooling directives such as `@vitest-environment jsdom` are kept), and
- documents no declaration: a blank line separates it from the code, nothing follows it, or the code that follows does not open with a declaration keyword such as `export`, `function`, `const` or `class`.

A one-line block comment and a line comment are left alone. The fix removes the comment and the whitespace after it.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * This is the vfs module.
 * It provides virtual file system utilities.
 */

export function createVfs() {}
```

```ts
/*
 * File: utils.ts
 * Description: Utility functions for the application
 */
describe('utils', () => {})
```

##### ✅ Correct

```ts
/**
 * Virtual file system utilities.
 *
 * @module vfs
 */

export function createVfs() {}
```

```ts
/**
 * Creates an empty virtual file system.
 * Paths are POSIX.
 */
export function createVfs() {}
```

```ts
/**
 * @vitest-environment jsdom
 */
describe('DOM tests', () => {})
```

---

### `no-deprecated-tag`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid the `@deprecated` tag in block comments.

#### Rule Details

The rule is for projects that ship breaking changes in a major version and remove the code they replace, rather than keeping it beside a deprecation warning. Deprecated code that stays accumulates, and a tag that says "use the other one" leaves two ways to do one thing. The rule reports the first `@deprecated` tag of every block comment, in any letter case, when the word is followed by whitespace, `*` or the end of the comment. A mention inside backticks or another word, such as `` `@deprecated` `` in prose, passes. The rule does not fix.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
/**
 * @deprecated Use newFunction instead
 */
export function oldFunction(): void {}
```

##### ✅ Correct

```ts
/**
 * Performs the operation. Replaces the previous implementation, removed in
 * the last major version.
 */
export function newFunction(): void {}
```

#### When Not To Use It

When a project keeps backwards compatibility across releases, runs long deprecation cycles, or publishes APIs whose users should be warned before something is removed.

---

### `no-enum`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid TypeScript `enum` declarations in favour of frozen const objects.

#### Rule Details

An `enum` compiles to a function call that bundlers cannot tree-shake, and it is one of the few TypeScript constructs with run-time behaviour of its own, such as the reverse mapping of a numeric enum. A frozen const object with `<const>` says the same thing, stays plain JavaScript, and a type derived from it gives the union of its values. The rule reports every `enum` declaration, `const enum` and `declare enum` included. It does not fix; its message shows the replacement to write.

#### Options

| Option                     | Type     | Default | Meaning                                                                                                                                                          |
| -------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`freezeImport`](#no-enum) | `string` | none    | An import statement the replacement in the message starts with, such as `"import { freeze } from 'my-utils'"`; the replacement then calls the imported function. |

Without it the message suggests `Object.freeze(...)`.

#### Examples

##### ❌ Incorrect

```ts
enum Status {
  Active = 'active',
  Inactive = 'inactive',
}

enum Direction {
  Up,
  Down,
}
```

##### ✅ Correct

```ts
const Status = Object.freeze(<const>{
  Active: 'active',
  Inactive: 'inactive',
})

type Status = (typeof Status)[keyof typeof Status]
```

#### When Not To Use It

When a project prefers enums, or relies on enum-only features such as the reverse mapping of numeric members.

---

### `no-inline-type-literal`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid anonymous object types with named members at use sites; declare the shape as a named type alias or interface.

#### Rule Details

An object type written inline, such as `{ a: number; b: string }` in a parameter annotation, is not a declaration, so it cannot carry JSDoc, cannot be imported or extended, and does not show up in an editor's symbol search. A change to the shape has to be repeated wherever the literal was copied. The rule reports every object type literal with at least one property or method member, wherever it sits: parameter and return annotations, variable and class property annotations, type assertions and `satisfies`, type arguments, unions and intersections, generic constraints, and literals nested inside a type alias. The rule does not fix.

Exempt are the literal that is the whole right-hand side of a `type` alias (the place a shape is named), an interface body, the empty type `{}`, and literals holding only index signatures (`{ [key: string]: T }`) or call signatures (`{ (): void }`), which have no named members to document.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
function start({ logger }: { logger: Logger }): void {}

function check(): { ok: boolean } {
  return { ok: true }
}

const m: Map<string, { a: number }> = new Map()

type Union = string | { a: number }

type Outer = { inner: { a: number } }
```

##### ✅ Correct

```ts
type StartOptions = { logger: Logger }
function start({ logger }: StartOptions): void {}

interface CheckResult {
  ok: boolean
}
function check(): CheckResult {
  return { ok: true }
}

type Inner = { a: number }
type Outer = { inner: Inner }

const empty: {} = {}
const counts: { [key: string]: number } = {}
```

---

### `no-manual-table-of-contents`

<p class="rule-facts"><span class="rule-fact">Reads Markdown</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid hand-written table-of-contents sections in markdown.

#### Rule Details

Documentation sites and repository hosts draw an on-page index from a document's headings. A table of contents written by hand says the same thing a second time, goes stale as soon as a heading changes, and takes the first screen of the page away from the content. The rule reports a heading, at any level, whose whole text names an index once letter case, repeated spaces and trailing punctuation are set aside. The remedy is to remove the heading and the list under it. The rule does not fix.

The headings reported are: Table of Contents, Table of Content, Contents, TOC, Index, Index of Contents, Document Index, Page Index, Section Index, Quick Index, Full Index, Document Contents, Page Contents, Section Contents, Quick Contents, In this document, In this page, In this section and In this guide.

Only headings are read, so the word "index" in a sentence, a list item or a code block is never reported, and a heading about something else, such as "Index Signatures" or "Indexing the cache", carries words that do not name a table of contents.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```markdown
# Architecture

### Table of Contents

1. [Overview](#overview)
2. [Design](#design)

### Overview
```

##### ✅ Correct

```markdown
# Architecture

### Overview

### Index Signatures

A mapped type with an index signature.
```

#### When Not To Use It

When the documents are read somewhere that draws no index from the headings, such as a plain-text viewer or a printed handout.

---

### `no-mixed-type-export`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid an export list that mixes inline `type` specifiers with value specifiers.

#### Rule Details

An export list that names types and values together hides which names survive compilation: the types are erased, the values stay. Keeping them in an `export type` statement and a plain export makes the split visible and gives tools that elide types one statement to drop. The rule reports an export list, a re-export or a local one, that holds both specifiers marked `type` and unmarked ones. The fix splits it into an `export type { … }` and an `export { … }` of the same source, keeping each specifier's alias.

A list whose specifiers are all marked `type`, or none of them, is not reported.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
export { type User, createUser } from './module'

export { type Config, type Options, initConfig as init } from './config'
```

##### ✅ Correct

```ts
export type { User } from './module'
export { createUser } from './module'

export type { Config, Options } from './config'
export { initConfig as init } from './config'
```

#### When Not To Use It

When a project prefers the brevity of inline type specifiers. The same split for imports is [no-mixed-type-import](#no-mixed-type-import).

---

### `no-mixed-type-import`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid an import that mixes inline `type` specifiers with value specifiers.

#### Rule Details

An import that names types and values together hides which names the compiled module still needs: the types are erased, the values stay. Keeping them in an `import type` statement and a plain import makes the split visible and gives tools that elide types one statement to drop. The rule reports an import whose named specifiers include both ones marked `type` and unmarked ones. The fix splits it into an `import type { … }` and a plain import of the same source; a default import stays with the values, and each specifier keeps its alias.

An import whose named specifiers are all marked `type`, or none of them, is not reported.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
import { Component, type ComponentProps, useState } from 'react'

import { helper, type HelperOptions as Options } from './utils'
```

##### ✅ Correct

```ts
import type { ComponentProps } from 'react'
import { Component, useState } from 'react'

import type { HelperOptions as Options } from './utils'
import { helper } from './utils'
```

#### When Not To Use It

When a project prefers the brevity of inline type specifiers. The same split for exports is [no-mixed-type-export](#no-mixed-type-export).

#### Limitations

A default import beside named specifiers that are all marked `type`, as in `import React, { type FC } from 'react'`, is not reported, since no named value specifier is present.

---

### `no-namespace-import`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid namespace imports (`import * as name`) in favour of named imports.

#### Rule Details

A namespace import hides which of a module's exports a file uses, and some bundlers keep every export of a module imported that way. Named imports say what is used and let unused exports be dropped. The rule reports each namespace import specifier. The rule does not fix.

Two kinds of namespace import are allowed: a type-only one (`import type * as Types from './types'`), which is erased at compile time, and one whose source ends in `.json`, since a JSON module has no named exports to pick.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
import * as utils from './utils'

utils.helper()
```

##### ✅ Correct

```ts
import { helper } from './utils'
import type * as Types from './types'
import * as config from './config.json'

helper()
```

#### When Not To Use It

For modules designed to be used as a namespace, or where a file deliberately groups a module's exports under one name.

#### Limitations

Namespace re-exports (`export * as utils from './utils'`) are not reported.

---

### `no-plain-inline-comments`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require every line comment to open with a hint prefix such as `why:` or to be a tooling directive.

#### Rule Details

A comment that restates the next line is noise, and one that explains a decision is easy to lose among them. The rule asks each `//` comment to say what kind of note it is, by opening with one of the hint prefixes below (in any letter case), or to be a directive some tool reads. Any other line comment is reported. Block comments are not read.

| Prefix     | Purpose                                                |
| ---------- | ------------------------------------------------------ |
| `why:`     | The rationale behind a decision that is not obvious    |
| `how:`     | An implementation approach that is not obvious         |
| `context:` | Background or an outside constraint                    |
| `magic:`   | The origin or meaning of a hard-coded value            |
| `todo:`    | Known work to be done                                  |
| `fixme:`   | A known defect                                         |
| `note:`    | A callout that fits no other kind                      |
| `ref:`     | A link to an outside resource, ticket or specification |
| `compat:`  | A shim kept only for a runtime below a version bound   |

A `compat:` comment names the runtime and the first version at which the shim can go, then why it exists, as in `compat: node<22 the WebSocket global arrived in Node 22`; searching for `compat: node<` then lists every shim a raised Node floor would retire.

The directives recognised are TypeScript's (`@ts-ignore`, `@ts-expect-error`, `@ts-nocheck`, `@ts-check`, triple-slash references), the linter's own (`lint-disable`, `lint-enable` and their line forms) and `eslint-env`, coverage hints (`istanbul ignore`, `c8 ignore`), bundler hints ([webpack's magic comments](https://webpack.js.org/api/module-methods/#magic-comments), `@vite-ignore`, `@rollup-plugin-ignore`), `prettier-ignore`, `//# sourceMappingURL=` and `//# sourceURL=`, fall-through markers (`// falls through`, `// fallthrough`, `// no default`), and `<hf:…>` region markers.

A comment that fills an otherwise empty function or catch body is left alone, and configuration files are skipped altogether: any file whose name contains a configuration name such as `tsconfig*.json`, `lint.config.*`, `eslint.config.*`, `vite.config.*`, `jest.config.*`, `webpack.config.*`, `rollup.config.*`, `prettier.config.*` or `package.json`.

The fix deletes the comment: its whole line when it stands alone, or the comment and the space before it when it trails code. Review the result, since a plain comment that held something worth keeping is better rewritten with a prefix.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
// Initialize the counter
let counter = 0

const x = 1 // increment later
```

##### ✅ Correct

```ts
// why: the API's indexes start at 0
let counter = 0

// magic: 86400 = seconds in a day (60 * 60 * 24)
const SECONDS_PER_DAY = 86400

// ref: https://github.com/org/repo/issues/123
function workaround() {}

try {
  workaround()
} catch {
  // ignored on purpose
}

// lint-disable-next-line no-console
console.log('Debug')
```

#### When Not To Use It

When a team prefers unrestricted commenting. A project that writes many comments spanning several lines should know that each continuation line is a comment of its own and must carry a prefix too.

---

### `no-section-dividers`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid section divider comments drawn with four or more equals signs.

#### Rule Details

A banner such as `// ==== Helpers ====` splits a file visually but not structurally, and a file long enough to need one usually wants separate modules, classes or functions instead. The rule reports every line comment containing `====`. When the divider opens a run of consecutive line comments that closes with another divider, as in a banner of three lines, the run is reported as one. The fix removes the divider, or the whole banner, together with the line break that ends it.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
// ============================
// User Management
// ============================

function createUser() {}

// ==== Helpers ====
function helper() {}
```

##### ✅ Correct

```ts
// note: user management
function createUser() {}

function helper() {}
```

---

### `no-todo-comments`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid TODO markers, in any spelling, in comments.

#### Rule Details

Work left for later belongs in an issue tracker, where it has an owner and stays visible; a TODO in the code goes stale unseen. The rule reports every occurrence of the marker in line, block and JSDoc comments, in any letter case and spelled as one word, hyphenated or spaced (TODO, to-do, to do), the `@todo` tag included. The marker must stand alone: a letter, digit, underscore or hyphen next to it makes it part of a longer word, so `path-to-document`, `auto download` and `todo-app` pass. The rule does not fix.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
// TODO: fix validation
```

```ts
/* TO-DO: refactor this */
```

```ts
/** @todo add error handling */
```

##### ✅ Correct

```ts
// note: validates the input format
// see path-to-document for details
// prevents an auto download of files
// the todo-app package handles this
```

#### When Not To Use It

When TODO comments are an accepted part of a project's workflow. The `todo:` prefix that [no-plain-inline-comments](#no-plain-inline-comments) allows is reported here, so a project that turns both rules on gives up that prefix.

#### Limitations

The spaced spelling is matched in ordinary prose too: a comment such as "the steps to do first" is reported.

---

### `no-unsafe-regex`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid regular expressions that risk catastrophic backtracking, and expressions built from values the code does not spell out.

#### Rule Details

A pattern with a repetition nested inside another, such as `/^(a+)+$/`, can take exponential time on a crafted input, which is a denial-of-service hole (ReDoS) wherever the input is untrusted. The rule reads every regular expression literal and every `RegExp(...)`, `new RegExp(...)` and [`createRegExp(...)`](https://www.hyperfrontend.dev/docs/libraries/utils/immutable-api/built-in-copy/regexp/#api-createRegExp) call whose pattern is a string or a template without substitutions, and reports a pattern that:

- holds a repetition inside another repetition, judged by star height the way the [safe-regex](https://www.npmjs.com/package/safe-regex2) package judges it, `?` counted as a repetition;
- holds more than 25 repetitions in all;
- names a quantifier upper bound past 1000, as in `{1,100000}`;
- cannot be read, such as one with a lookbehind.

A `RegExp` or [`createRegExp`](https://www.hyperfrontend.dev/docs/libraries/utils/immutable-api/built-in-copy/regexp/#api-createRegExp) call whose pattern is computed (a variable, a call, a template with substitutions) is reported too, since the pattern may come from input. The rule does not fix.

#### Options

This rule has no options. The thresholds are fixed: a bound of 1000 and 25 repetitions. Settings that similar rules offer, such as configurable thresholds, ignored patterns, extra factory functions or turning off the dynamic-construction check, are not supported.

#### Examples

##### ❌ Incorrect

```ts
const nested = /^(a+)+$/
const starred = /([a-zA-Z]+)*$/
const bounded = /a{1,100000}/

const dynamic = new RegExp(userInput)
const templated = new RegExp(`^${prefix}`)
```

##### ✅ Correct

```ts
const flat = /^a+$/
const word = /[a-zA-Z]+$/
const bounded = /a{1,100}/

const constant = new RegExp('^[a-z]+$', 'i')
```

#### Limitations

Like safe-regex, the check does not look inside a repeated group with alternatives, so overlapping alternatives such as `/(a|a)+/` pass, and an exact bound such as `{5000}` is not measured.

See [OWASP on ReDoS](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS) for background.

---

### `one-assertion-per-test`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Limit each test body to one assertion, counting the assertions reached through same-file helpers.

#### Rule Details

A unit test describes one behaviour. A test with two assertions names two behaviours at once, stops at the first failure and hides the second, and needs a title vague enough to cover both. The rule reports every test whose body reaches more than one assertion, on the declaring call, and names where the assertions are, so the author can choose between two remedies:

- **Split** the test into focused tests, each titled for the single behaviour it asserts.
- **Fold** the checks into one assertion when they jointly describe one indivisible behaviour, with a composite or asymmetric matcher such as `toEqual(expect.objectContaining({ ... }))` or `toMatchObject(...)`. A fold should still name what failed: compare a keyed object (`{ before, after }`) rather than a positional array of booleans whose failure reads `[true, false]`.

Which remedy fits is a judgement about the behaviour under test, so the rule does not fix. It never requires an assertion: a test with none is left alone.

##### What is read

Tests are calls such as `it(...)`, `test(...)`, `fit(...)`, `xit(...)` and `xtest(...)`, modifier chains such as `it.only(...)`, `test.skip(...)`, `it.todo(...)`, `it.failing(...)` and `it.concurrent(...)` included, and the table forms such as `it.each(table)(...)`. The body is the first argument that is a function, or a name bound to a function in the same file. Suites and hooks are not tests, so assertions in them are not counted.

Assertions are `expect(...)` (under any local alias), `expect.soft(...)` and `expect.poll(...)`, and every call into the assert module, imported from `node:assert`, `node:assert/strict`, `assert` or `assert/strict` as a default, a namespace or named functions. Matcher builders (`expect.any(...)`, `expect.objectContaining(...)`, `expect.not.*` and the like) and the count declarations `expect.assertions(n)` and `expect.hasAssertions()` are not assertions.

##### How assertions are counted

The count is lexical: every assertion written in the body counts once, including those inside nested callbacks such as an `items.forEach(...)` callback or a mock implementation. A loop that asserts once per element is one assertion over a collection; an `if`/`else` asserting in both branches is two. A reference to a function declared in the same file, called or passed as a callback, adds every assertion that function reaches, through further helpers too, so a helper called twice counts twice. A test declared inside another test is reported on its own and adds nothing to its parent.

#### Options

This rule has no options. To leave files alone, such as fixture suites whose assertion shape is itself under test, scope the rule with the configuration's [`files`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-ConfigBlock-prop-files) and [`ignores`](https://www.hyperfrontend.dev/docs/libraries/linter/#api-ConfigBlock-prop-ignores).

#### Examples

##### ❌ Incorrect

```ts
it('parses the manifest', () => {
  const manifest = parse(source)
  expect(manifest.name).toBe('demo')
  expect(manifest.version).toBe('1.2.3')
})

function expectValid(result: Result): void {
  expect(result.ok).toBe(true)
  expect(result.errors).toEqual([])
}

it('validates the manifest', () => {
  expectValid(validate(manifest))
})
```

##### ✅ Correct

```ts
it('parses the manifest identity', () => {
  const manifest = parse(source)
  expect(manifest).toEqual(expect.objectContaining({ name: 'demo' }))
})

it('validates the manifest', () => {
  expect(validate(manifest)).toEqual({ ok: true, errors: [] })
})

it('reports every item as defined', () => {
  items.forEach((item) => expect(item).toBeDefined())
})

it('declares its assertion count', () => {
  expect.assertions(1)
  expect(add(1, 2)).toBe(3)
})
```

#### When Not To Use It

For suites written as integration scenarios that walk through many states in one test, where a split would break the scenario. Scope the rule away from those files rather than switching it off for a project.

#### Limitations

The rule reads one file at a time and has no type information. An assertion helper imported from another module, a method called on a class instance, and a body built by a call (`it('x', makeBody())`) are not seen.

---

### `prefer-exec-file-sync`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Forbid [`execSync`](https://nodejs.org/api/child_process.html#child_processexecsynccommand-options) from the child process module in favour of [`execFileSync`](https://nodejs.org/api/child_process.html#child_processexecfilesyncfile-args-options).

#### Rule Details

[`execSync`](https://nodejs.org/api/child_process.html#child_processexecsynccommand-options) runs its command string through a shell. Anything interpolated into the string is parsed by that shell, so a path with a space breaks the command and untrusted input can inject one; quoting rules also differ between bash, cmd and PowerShell. [`execFileSync`](https://nodejs.org/api/child_process.html#child_processexecfilesyncfile-args-options) runs the executable directly with an argument array that no shell sees. The rule reports [`execSync`](https://nodejs.org/api/child_process.html#child_processexecsynccommand-options) wherever it is taken from `child_process` or `node:child_process`:

- a named import, or a property destructured from `require()` of the module;
- a member read through a namespace, default import or required module object, dotted or bracketed (`cp.execSync(...)`, `cp['execSync'](...)`).

The rule does not fix: moving to [`execFileSync`](https://nodejs.org/api/child_process.html#child_processexecfilesyncfile-args-options) means splitting the command into the executable and its arguments, and replacing shell features with Node code.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
import { execSync } from 'node:child_process'

execSync(`git add ${filePath}`)
```

```ts
import * as cp from 'node:child_process'

cp.execSync('npm install')
```

```ts
const { execSync } = require('node:child_process')
```

##### ✅ Correct

```ts
import { execFileSync } from 'node:child_process'

execFileSync('git', ['add', filePath])
execFileSync('git', ['commit', '-m', 'a message with spaces'])
```

#### When Not To Use It

When a script needs shell features such as pipes, redirects or globbing on purpose. Node APIs usually cover those without a shell.

#### Limitations

Only the synchronous function is covered: [`exec`](https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback) and the `shell: true` option of the other functions also run through a shell and are not reported.

---

### `prefer-jsdoc-over-trailing-comments`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require interface members to be documented by a JSDoc block above them, not by a trailing line comment.

#### Rule Details

Documentation tools such as TypeDoc and editors' hover cards collect a member's JSDoc block and ignore a `//` comment trailing it on the same line, so the description is lost wherever the member is read. The rule reports a line comment that follows an interface member on the member's own line. The fix moves the comment's text into a `/** … */` block above the member, at the member's indentation. When the member already has a JSDoc block above it, the rule reports without a fix, so existing documentation is never overwritten.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
interface User {
  id: string // unique identifier
  name: string // display name
}
```

##### ✅ Correct

```ts
interface User {
  /** Unique identifier */
  id: string
  /** Display name */
  name: string
}
```

#### Limitations

Only interface bodies are read. Members of a type literal, a class or an object literal with a trailing comment are not reported.

---

### `readme-paragraph-length`

<p class="rule-facts"><span class="rule-fact">Reads Markdown</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Report markdown paragraphs that have grown into walls of text.

#### Rule Details

A paragraph is the unit a reader commits to before a break. Past a certain length the eye loses its place returning to the margin, the reader cannot tell which sentence carries the point, and a summariser has no boundary to summarise around. The remedy is rarely a break at the midpoint: it is one idea per paragraph, or fewer words. The rule reports a paragraph longer than [`maxCharacters`](#readme-paragraph-length). It does not fix.

The rule reads the markdown tree, so code blocks, tables, headings, HTML blocks and link definitions are never mistaken for prose. It measures rendered characters, not source characters:

| Node                         | Contributes                       |
| ---------------------------- | --------------------------------- |
| text and inline code         | its text                          |
| link, link reference         | the link text only, never the URL |
| emphasis, strong, delete     | the text inside                   |
| image, image reference       | nothing                           |
| inline HTML, hard line break | nothing                           |

Runs of whitespace collapse to one space before the count, so a paragraph hard-wrapped over ten source lines measures the same as one written on a single line. A paragraph inside a list item, a blockquote, a table cell or a footnote definition is exempt: those are fragments whose length the surrounding structure governs.

#### Options

| Option                      | Type     | Default | Meaning                                                          |
| --------------------------- | -------- | ------- | ---------------------------------------------------------------- |
| [`maxCharacters`](#readme-paragraph-length) | `number` | `700`   | Rendered characters a paragraph may reach before it is reported. |

Seven hundred is about six lines at a typical documentation column of 115 characters, and sits above the 95th percentile of paragraph length in a sample of nearly a thousand library README paragraphs, so the rule flags genuine walls of text and stays silent on ordinary technical writing.

#### Examples

##### ❌ Incorrect, with { "maxCharacters": 200 }

```markdown
The host owns the geometry and the feature never measures itself, which
means the contract declares every display mode up front, and the host picks
one at open time and passes the measured size across, and because the
feature cannot ask for a different size its only lever is to refuse a mode.
```

##### ✅ Correct, with { "maxCharacters": 200 }

```markdown
The host owns the geometry: a feature never measures itself. The contract
declares every display mode, and the host picks one at open time.

A feature's only lever is refusal: it can decline a mode it cannot render.

- A list item is a fragment, so its length is left to the list around it,
  however many words it takes to describe the step it stands for in full.
```

#### When Not To Use It

For generated documents, or transcripts that must keep their original paragraphing. Raising [`maxCharacters`](#readme-paragraph-length) is the better lever when a whole package's documentation is legitimately denser than the rest.

---

### `require-codeblock-language`

<p class="rule-facts"><span class="rule-fact">Reads Markdown</span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require a language on every fenced code block in markdown.

#### Rule Details

The language after the opening fence is what lets a renderer highlight the block, a screen reader announce it, and tools such as [codeblock-line-width](#codeblock-line-width) tell code from output. A reader also knows at a glance what they are looking at. The rule reports an opening fence of backticks with nothing after it. For output or plain text, use the language text or console. The rule does not fix.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

````markdown
```
const x = 1
```
````

##### ✅ Correct

````markdown
```ts
const x = 1
```

```json
{ "name": "example" }
```

```text
This is plain text output
```
````

#### Limitations

Fences are paired line by line without regard to their length, so a block fenced with four backticks that shows a three-backtick fence inside it is not read the way a markdown renderer reads it. Fences of tildes are not checked.

---

### `require-node-protocol`

<p class="rule-facts"><span class="rule-fact">Reads TypeScript, JavaScript</span><span class="rule-fact rule-fact--fix">🔧 Fixable with <code>--fix</code></span><span class="rule-fact rule-fact--muted">No preset: turn it on by id</span></p>

Require the `node:` prefix on imports of Node built-in modules.

#### Rule Details

The `node:` prefix names a built-in unambiguously: a reader tells it from an npm package at a glance, and a package published under the same name can never shadow it. The rule reports an import whose source is a Node built-in written without the prefix, judged by its first path segment against the running Node's list of built-ins, so `fs/promises` counts as well as `fs`. The fix adds the prefix, keeping the quote style.

#### Options

This rule has no options.

#### Examples

##### ❌ Incorrect

```ts
import { readFileSync } from 'fs'
import path from 'path'
import { setTimeout } from 'timers/promises'
```

##### ✅ Correct

```ts
import { readFileSync } from 'node:fs'
import path from 'node:path'
import { setTimeout } from 'node:timers/promises'
import express from 'express'
```

#### When Not To Use It

When the code must run on a Node too old for the prefix (before 14.18 for `require()`, before 12.20 for ES modules).

#### Limitations

Only import declarations are read. `require()` calls, dynamic `import()` expressions and re-exports (`export * from 'fs'`) are not reported.

---

Canonical page: https://www.hyperfrontend.dev/docs/libraries/linter/rules/
This file: https://www.hyperfrontend.dev/docs/libraries/linter/rules.md
Documentation index: https://www.hyperfrontend.dev/llms.txt
