diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro
index 12d1517..f24f4bc 100644
--- a/src/layouts/Base.astro
+++ b/src/layouts/Base.astro
@@ -10,7 +10,7 @@ interface Props {
const {
title,
- description = 'A fast, type-aware TypeScript 7 linter. Drop-in compatible with typescript-eslint.',
+ description = 'A fast, type-aware TypeScript 7 linter. Rule-compatible with typescript-eslint.',
} = Astro.props;
const fullTitle = title === 'jetlint' ? title : `${title} · jetlint`;
diff --git a/src/pages/config.md b/src/pages/config.md
index d99ea43..7d05541 100644
--- a/src/pages/config.md
+++ b/src/pages/config.md
@@ -33,14 +33,14 @@ A rule entry can be a string for severity or an array of `[severity, options]`:
{
"rules": {
"no-floating-promises": "error",
- "prefer-nullish-coalescing": "warn",
+ "prefer-nullish-coalescing": "warning",
"no-unused-vars": "off",
"only-throw-error": ["error", { "allowThrowingAny": false }]
}
}
```
-Valid severities: `"error"`, `"warn"`, `"off"`.
+Valid severities: `"error"`, `"warning"`, `"off"`.
## Per-rule options
@@ -75,15 +75,69 @@ project/
jetlint resolves files using your `tsconfig.json`'s `include` / `exclude`.
Pass `--project ./tsconfig.json` to point at a specific config file.
+## Ignoring files
+
+`ignorePatterns` is a list of gitignore-flavored doublestar globs that
+suppress diagnostics for matching files. Matched files stay part of the
+TypeScript program — their type information is still available to
+importers — only diagnostic emission is suppressed.
+
+```json
+{
+ "ignorePatterns": [
+ "**/generated/**",
+ "packages/*/lib/**/*.gen.ts",
+ "!packages/keep/lib/api/keep.gen.ts"
+ ]
+}
+```
+
+- A leading `!` un-ignores.
+- Patterns resolve relative to the directory of the `.jetlintrc.json`
+ that contains them.
+- In a multi-config cascade, negation patterns from inner configs apply
+ across the cascade so a child can subtract from a parent's positive
+ ignore.
+
+Unknown top-level keys (e.g. `ignoreFiles` instead of `ignorePatterns`)
+exit with code `2` and a structured error so typos can't quietly
+disable a feature.
+
+Available from `@jetlint/cli@0.1.6`.
+
+## Limiting diagnostic output
+
+`--max-diagnostics N` caps the number of error diagnostics the human
+formatter renders, and short-circuits the lint walk once the threshold
+is hit. On large projects this turns a full multi-second lint into a
+sub-second “is anything broken?” answer.
+
+```bash
+# Bail out after the first 20 errors. Default is 20.
+jetlint --max-diagnostics 20
+
+# No cap: visit every node, render every diagnostic.
+jetlint --max-diagnostics 0
+```
+
+The cap only applies to the human formatter. Machine formats (`json`,
+`sarif`, `github`, `junit`, `rdjson`) always return the full diagnostic
+set so downstream tools aren't silently truncated. Warning-severity
+diagnostics (including the engine's own `jetlint/rule-panic`
+recoveries) don't consume the cap, so a buggy rule can't stop you
+seeing real findings.
+
+Available from `@jetlint/cli@0.1.7`.
+
## Editor and CI configs
-The same `.jetlintrc.json` is used everywhere. For CI-specific overrides
-(e.g. promoting `warn` to `error`), launch jetlint with `--strict`. That
-treats every `warn` as `error` for that run.
+The same `.jetlintrc.json` is used everywhere. CI invocations typically
+pair `--max-diagnostics 0` (to see every finding) with `--format json`
+or `--format sarif` (so downstream tools can parse the diagnostics).
## Coming next: category-level severity
-Rules are already grouped into [seven categories](/rules/#all-rules-by-category)
+Rules are already grouped into [eight categories](/rules/#all-rules-by-category)
internally. A future release will let you set severity per category in
addition to per rule:
@@ -91,7 +145,7 @@ addition to per rule:
{
"categories": {
"correctness": "error",
- "performance": "warn",
+ "performance": "warning",
"style": "off"
},
"rules": {
diff --git a/src/pages/index.astro b/src/pages/index.astro
index fc8fa7f..38fde49 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -7,9 +7,9 @@ import Base from '../layouts/Base.astro';
jetlint · pre-1.0
Type-aware TypeScript 7 linting.
Without the wait.
- A fast, type-aware linter for the TypeScript 7 native (Go) toolchain. Drop-in
- compatible with typescript-eslint: the rules you already configure, reporting in
- a fraction of the time.
+ A fast, type-aware linter for the TypeScript 7 native (Go) toolchain.
+ Rule-compatible with typescript-eslint — the rule names and options you
+ already use, reporting in a fraction of the time.
Get started
@@ -20,8 +20,8 @@ import Base from '../layouts/Base.astro';
100%
- 10598 / 10598 upstream fixtures pass across 182 rules
- (61 typescript-eslint ports + 112 biome / oxlint ports), plus hand-written tests
+ 11652 / 11652 upstream fixtures pass across 373 rules
+ (61 typescript-eslint ports + 303 biome / oxlint ports), plus hand-written tests
for 9 ESLint-core rules without upstream fixture data.
Same diagnostics as the upstream tools, byte-for-byte against their published test suites.
@@ -32,11 +32,12 @@ import Base from '../layouts/Base.astro';
Type-aware linting at native speed.
-
Interactive speed
+
Fail-fast lints
- Re-lints reuse a warm TypeScript program. The first lint pays for the load;
- every lint after that returns in milliseconds, fast enough to sit inside an
- edit-feedback loop.
+ Use --max-diagnostics N to bail out of the lint walk after the
+ first N errors. On a real project, capping at 20 turns a 80 s full
+ lint into a 0.4 s answer for “does this branch have any
+ violations?”
@@ -50,8 +51,8 @@ import Base from '../layouts/Base.astro';
Faithful compatibility
Every rule is verified against upstream fixtures: 6193 typescript-eslint cases
- and 4405 biome / oxlint cases, plus hand-written tests for 9 ESLint-core rules
- without upstream fixtures. 100% match across all 182 rules. Switch over
+ and 5459 biome / oxlint cases, plus hand-written tests for 9 ESLint-core rules
+ without upstream fixtures. 100% match across all 373 rules. Switch over
without re-learning your config.
@@ -80,12 +81,13 @@ import Base from '../layouts/Base.astro';
-
182 rules, organized into 7 categories.
+
373 rules, organized into 8 categories.
- correctness 105
- - suspicious 31
- - complexity 17
- - style 7
+ - suspicious 97
+ - style 61
+ - complexity 52
+ - a11y 36
- performance 16
- security 6
- nursery 0
@@ -134,7 +136,8 @@ npx jetlint --project ./tsconfig.json`}
in seconds-to-minutes, which is too slow to sit inside an inner loop. With the
TypeScript 7 native toolchain landing, the checker itself is finally fast enough
that a thin linter on top can return type-aware diagnostics at interactive speed,
- especially when a daemon keeps the program warm between runs.
+ and a --max-diagnostics bail-out turns the “is anything broken?”
+ question into a sub-second answer even on big projects.
Standing on other peoples' shoulders.
@@ -143,7 +146,8 @@ npx jetlint --project ./tsconfig.json`}
problems (what the rules should mean, how the checker should answer type queries,
how a linter should be structured) have already been solved well elsewhere.
jetlint's contribution is wiring them together for the TS 7 native checker
- with a daemon in front.
+ and exposing the ergonomic switches (fast bail-out, predictable config) that make
+ it useful in an inner loop.
-
diff --git a/src/pages/install.md b/src/pages/install.md
index cde9669..fca241f 100644
--- a/src/pages/install.md
+++ b/src/pages/install.md
@@ -63,7 +63,7 @@ jetlint --project ./tsconfig.json
```
By default, jetlint applies the **5 recommended rules** at `error` severity. The other
-**177 rules** ship `off`; see [Config](/config/) to opt in.
+**368 rules** ship `off`; see [Config](/config/) to opt in.
## Run as a daemon
diff --git a/src/pages/roadmap.md b/src/pages/roadmap.md
index 21e9c73..565db7b 100644
--- a/src/pages/roadmap.md
+++ b/src/pages/roadmap.md
@@ -30,7 +30,7 @@ from correctness.
### [suspicious](https://github.com/jetlint/jetlint/milestone/2)
Code that smells. Usually wrong, occasionally intentional. The author
-should justify or fix. Default severity is `warn`.
+should justify or fix. Default severity is `warning`.
### [security](https://github.com/jetlint/jetlint/milestone/3)
diff --git a/src/pages/rules.md b/src/pages/rules.md
index 2ec08f4..56b1ef0 100644
--- a/src/pages/rules.md
+++ b/src/pages/rules.md
@@ -1,21 +1,21 @@
---
layout: ../layouts/Base.astro
title: Rules
-description: All 182 jetlint rules, organized into 7 categories. 5 in the recommended preset; the rest opt-in.
+description: All 373 jetlint rules, organized into 8 categories. 5 in the recommended preset; the rest opt-in.
---
# Rules
-jetlint ships **182 rules** organized into **7 categories**. Five
+jetlint ships **373 rules** organized into **8 categories**. Five
rules form the **recommended preset** and fire at `error` severity by
default; every other rule is `off` until opted in via
[`.jetlintrc.json`](/config/).
**Compatibility.** 6193 / 6193 typescript-eslint fixtures pass, plus
-4405 / 4405 AST-only fixtures across the 112 biome and
+5459 / 5459 AST-only fixtures across the 303 biome and
oxlint ports, plus 71 / 71 hand-written tests for the 9
ESLint-core rules without upstream fixture data — **100% across the
-board** (10669 cases total). Every rule's score is reproducible from
+board** (11723 cases total). Every rule's score is reproducible from
the [jetlint repo](https://github.com/jetlint/jetlint).
**Origin.** Type-aware rules were ported from
@@ -47,7 +47,7 @@ add others, opt in by name. See [Config](/config/).
## All rules, by category
-The seven categories follow the rubric in
+The eight categories follow the rubric in
[`docs/RULE-CATEGORIES.md`](https://github.com/jetlint/jetlint/blob/main/docs/RULE-CATEGORIES.md):
the first matching framing wins, with `correctness` beating
`performance` beating `complexity` for cross-cutting rules. A ★
@@ -165,43 +165,109 @@ Code that is wrong: runtime bugs, undefined behavior, type holes. No legitimate
| [`use-yield`](https://eslint.org/docs/latest/rules/use-yield) | AST-only | 17 / 17 |
| [`valid-typeof`](https://eslint.org/docs/latest/rules/valid-typeof) | AST-only | 60 / 60 |
-### suspicious — 31 rules
+### suspicious — 97 rules
Code that smells. Usually wrong, occasionally intentional. The author should justify or fix.
| Rule | Mode | Fixtures |
|---|:-:|---:|
+| [`adjacent-overload-signatures`](https://eslint.org/docs/latest/rules/adjacent-overload-signatures) | AST-only | 64 / 64 |
+| [`default-case-last`](https://eslint.org/docs/latest/rules/default-case-last) | AST-only | 37 / 37 |
| [`getter-return`](https://eslint.org/docs/latest/rules/getter-return) | AST-only | 85 / 85 |
+| [`guard-for-in`](https://eslint.org/docs/latest/rules/guard-for-in) | AST-only | 12 / 12 |
+| [`no-alert`](https://biomejs.dev/linter/rules/noAlert) | AST-only | 2 / 2 |
+| [`no-approximative-numeric-constant`](https://biomejs.dev/linter/rules/noApproximativeNumericConstant) | AST-only | 2 / 2 |
+| [`no-array-index-key`](https://biomejs.dev/linter/rules/noArrayIndexKey) | AST-only | 2 / 2 |
+| [`no-assign-in-expressions`](https://biomejs.dev/linter/rules/noAssignInExpressions) | AST-only | 3 / 3 |
| [`no-async-promise-executor`](https://eslint.org/docs/latest/rules/no-async-promise-executor) | AST-only | 6 / 6 |
+| [`no-bitwise-operators`](https://biomejs.dev/linter/rules/noBitwiseOperators) | AST-only | 2 / 2 |
+| [`no-catch-assign`](https://biomejs.dev/linter/rules/noCatchAssign) | AST-only | 1 / 1 |
| [`no-class-assign`](https://eslint.org/docs/latest/rules/no-class-assign) | AST-only | 25 / 25 |
+| [`no-comment-text`](https://biomejs.dev/linter/rules/noCommentText) | AST-only | 2 / 2 |
| [`no-compare-neg-zero`](https://eslint.org/docs/latest/rules/no-compare-neg-zero) | AST-only | 40 / 40 |
+| [`no-confusing-labels`](https://biomejs.dev/linter/rules/noConfusingLabels) | AST-only | 20 / 20 |
| [`no-confusing-void-expression`](https://typescript-eslint.io/rules/no-confusing-void-expression) | type-aware | 108 / 108 |
+| [`no-confusing-void-type`](https://biomejs.dev/linter/rules/noConfusingVoidType) | AST-only | 2 / 2 |
+| [`no-console`](https://biomejs.dev/linter/rules/noConsole) | AST-only | 4 / 4 |
+| [`no-const-enum`](https://biomejs.dev/linter/rules/noConstEnum) | AST-only | 1 / 1 |
| [`no-constant-binary-expression`](https://eslint.org/docs/latest/rules/no-constant-binary-expression) | AST-only | 251 / 251 |
| [`no-control-regex`](https://eslint.org/docs/latest/rules/no-control-regex) | AST-only | 8 hand-written |
| [`no-debugger`](https://eslint.org/docs/latest/rules/no-debugger) | AST-only | 2 / 2 |
| [`no-deprecated`](https://typescript-eslint.io/rules/no-deprecated) | type-aware | 262 / 262 |
+| [`no-deprecated-imports`](https://biomejs.dev/linter/rules/noDeprecatedImports) | AST-only | 4 / 4 |
+| [`no-document-cookie`](https://biomejs.dev/linter/rules/noDocumentCookie) | AST-only | 2 / 2 |
+| [`no-document-import-in-page`](https://biomejs.dev/linter/rules/noDocumentImportInPage) | AST-only | 1 / 1 |
+| [`no-double-equals`](https://biomejs.dev/linter/rules/noDoubleEquals) | AST-only | 7 / 7 |
| [`no-dupe-args`](https://eslint.org/docs/latest/rules/no-dupe-args) | AST-only | 5 hand-written |
| [`no-dupe-class-members`](https://eslint.org/docs/latest/rules/no-dupe-class-members) | AST-only | 74 / 74 |
| [`no-dupe-else-if`](https://eslint.org/docs/latest/rules/no-dupe-else-if) | AST-only | 89 / 89 |
| [`no-dupe-keys`](https://eslint.org/docs/latest/rules/no-dupe-keys) | AST-only | 50 / 50 |
| [`no-duplicate-case`](https://eslint.org/docs/latest/rules/no-duplicate-case) | AST-only | 30 / 30 |
+| [`no-duplicate-jsx-props`](https://biomejs.dev/linter/rules/noDuplicateJsxProps) | AST-only | 2 / 2 |
+| [`no-duplicate-test-hooks`](https://biomejs.dev/linter/rules/noDuplicateTestHooks) | AST-only | 2 / 2 |
+| [`no-empty`](https://eslint.org/docs/latest/rules/no-empty) | AST-only | 34 / 34 |
+| [`no-empty-interface`](https://biomejs.dev/linter/rules/noEmptyInterface) | AST-only | 3 / 3 |
+| [`no-empty-source`](https://biomejs.dev/linter/rules/noEmptySource) | AST-only | 11 / 11 |
+| [`no-evolving-types`](https://biomejs.dev/linter/rules/noEvolvingTypes) | AST-only | 2 / 2 |
+| [`no-explicit-any`](https://biomejs.dev/linter/rules/noExplicitAny) | AST-only | 6 / 6 |
+| [`no-exports-in-test`](https://biomejs.dev/linter/rules/noExportsInTest) | AST-only | 5 / 5 |
+| [`no-extra-non-null-assertion`](https://biomejs.dev/linter/rules/noExtraNonNullAssertion) | AST-only | 2 / 2 |
| [`no-fallthrough`](https://eslint.org/docs/latest/rules/no-fallthrough) | AST-only | 86 / 86 |
+| [`no-focused-tests`](https://biomejs.dev/linter/rules/noFocusedTests) | AST-only | 2 / 2 |
+| [`no-function-assign`](https://biomejs.dev/linter/rules/noFunctionAssign) | AST-only | 13 / 13 |
+| [`no-global-assign`](https://biomejs.dev/linter/rules/noGlobalAssign) | AST-only | 2 / 2 |
+| [`no-global-is-finite`](https://biomejs.dev/linter/rules/noGlobalIsFinite) | AST-only | 2 / 2 |
+| [`no-global-is-nan`](https://biomejs.dev/linter/rules/noGlobalIsNan) | AST-only | 2 / 2 |
+| [`no-head-import-in-document`](https://biomejs.dev/linter/rules/noHeadImportInDocument) | AST-only | 0 / 0 |
+| [`no-implicit-any-let`](https://biomejs.dev/linter/rules/noImplicitAnyLet) | AST-only | 2 / 2 |
| [`no-import-assign`](https://eslint.org/docs/latest/rules/no-import-assign) | AST-only | 116 / 116 |
+| [`no-import-cycles`](https://biomejs.dev/linter/rules/noImportCycles) | AST-only | 4 / 4 |
+| [`no-instanceof-array`](https://eslint.org/docs/latest/rules/no-instanceof-array) | AST-only | 17 / 17 |
| [`no-irregular-whitespace`](https://eslint.org/docs/latest/rules/no-irregular-whitespace) | AST-only | 220 / 220 |
+| [`no-label-var`](https://biomejs.dev/linter/rules/noLabelVar) | AST-only | 2 / 2 |
| [`no-misleading-character-class`](https://eslint.org/docs/latest/rules/no-misleading-character-class) | AST-only | 6 hand-written |
+| [`no-misplaced-assertion`](https://biomejs.dev/linter/rules/noMisplacedAssertion) | AST-only | 9 / 9 |
+| [`no-misrefactored-shorthand-assign`](https://biomejs.dev/linter/rules/noMisrefactoredShorthandAssign) | AST-only | 2 / 2 |
+| [`no-misused-new`](https://eslint.org/docs/latest/rules/no-misused-new) | AST-only | 19 / 19 |
+| [`no-non-null-asserted-optional-chain`](https://biomejs.dev/linter/rules/noNonNullAssertedOptionalChain) | AST-only | 2 / 2 |
+| [`no-octal-escape`](https://biomejs.dev/linter/rules/noOctalEscape) | AST-only | 2 / 2 |
| [`no-prototype-builtins`](https://eslint.org/docs/latest/rules/no-prototype-builtins) | AST-only | 47 / 47 |
+| [`no-react-forward-ref`](https://biomejs.dev/linter/rules/noReactForwardRef) | AST-only | 7 / 7 |
+| [`no-react-specific-props`](https://biomejs.dev/linter/rules/noReactSpecificProps) | AST-only | 2 / 2 |
+| [`no-redeclare`](https://biomejs.dev/linter/rules/noRedeclare) | AST-only | 51 / 51 |
+| [`no-redundant-use-strict`](https://biomejs.dev/linter/rules/noRedundantUseStrict) | AST-only | 15 / 15 |
| [`no-self-compare`](https://eslint.org/docs/latest/rules/no-self-compare) | AST-only | 24 / 24 |
+| [`no-shadow-restricted-names`](https://biomejs.dev/linter/rules/noShadowRestrictedNames) | AST-only | 7 / 7 |
+| [`no-skipped-tests`](https://biomejs.dev/linter/rules/noSkippedTests) | AST-only | 2 / 2 |
| [`no-sparse-arrays`](https://eslint.org/docs/latest/rules/no-sparse-arrays) | AST-only | 9 / 9 |
+| [`no-suspicious-semicolon-in-jsx`](https://biomejs.dev/linter/rules/noSuspiciousSemicolonInJsx) | AST-only | 2 / 2 |
| [`no-template-curly-in-string`](https://eslint.org/docs/latest/rules/no-template-curly-in-string) | AST-only | 23 / 23 |
+| [`no-then-property`](https://biomejs.dev/linter/rules/noThenProperty) | AST-only | 2 / 2 |
+| [`no-ts-ignore`](https://biomejs.dev/linter/rules/noTsIgnore) | AST-only | 1 / 1 |
+| [`no-unassigned-variables`](https://biomejs.dev/linter/rules/noUnassignedVariables) | AST-only | 4 / 4 |
| [`no-unexpected-multiline`](https://eslint.org/docs/latest/rules/no-unexpected-multiline) | AST-only | 58 / 58 |
+| [`no-unsafe-declaration-merging`](https://biomejs.dev/linter/rules/noUnsafeDeclarationMerging) | AST-only | 2 / 2 |
| [`no-unsafe-negation`](https://eslint.org/docs/latest/rules/no-unsafe-negation) | AST-only | 30 / 30 |
| [`no-unsafe-type-assertion`](https://typescript-eslint.io/rules/no-unsafe-type-assertion) | type-aware | 15 / 15 |
+| [`no-unused-expressions`](https://eslint.org/docs/latest/rules/no-unused-expressions) | AST-only | 110 / 110 |
+| [`no-useless-escape-in-string`](https://biomejs.dev/linter/rules/noUselessEscapeInString) | AST-only | 3 / 3 |
+| [`no-useless-regex-backrefs`](https://biomejs.dev/linter/rules/noUselessRegexBackrefs) | AST-only | 3 / 3 |
+| [`no-var`](https://biomejs.dev/linter/rules/noVar) | AST-only | 14 / 14 |
+| [`no-with`](https://eslint.org/docs/latest/rules/no-with) | AST-only | 12 / 12 |
+| [`prefer-namespace-keyword`](https://eslint.org/docs/latest/rules/prefer-namespace-keyword) | AST-only | 10 / 10 |
| [`promise-function-async`](https://typescript-eslint.io/rules/promise-function-async) | type-aware | 53 / 53 |
| [`restrict-plus-operands`](https://typescript-eslint.io/rules/restrict-plus-operands) | type-aware | 119 / 119 |
| [`restrict-template-expressions`](https://typescript-eslint.io/rules/restrict-template-expressions) | type-aware | 79 / 79 |
| [`return-await`](https://typescript-eslint.io/rules/return-await) | type-aware | 95 / 95 |
| [`strict-boolean-expressions`](https://typescript-eslint.io/rules/strict-boolean-expressions) | type-aware | 214 / 214 |
| [`unbound-method`](https://typescript-eslint.io/rules/unbound-method) | type-aware | 202 / 202 |
+| [`use-await`](https://biomejs.dev/linter/rules/useAwait) | AST-only | 2 / 2 |
+| [`use-error-message`](https://biomejs.dev/linter/rules/useErrorMessage) | AST-only | 2 / 2 |
+| [`use-google-font-display`](https://biomejs.dev/linter/rules/useGoogleFontDisplay) | AST-only | 2 / 2 |
+| [`use-iterable-callback-return`](https://biomejs.dev/linter/rules/useIterableCallbackReturn) | AST-only | 2 / 2 |
+| [`use-number-to-fixed-digits-argument`](https://biomejs.dev/linter/rules/useNumberToFixedDigitsArgument) | AST-only | 2 / 2 |
+| [`use-static-response-methods`](https://biomejs.dev/linter/rules/useStaticResponseMethods) | AST-only | 2 / 2 |
+| [`use-strict-mode`](https://biomejs.dev/linter/rules/useStrictMode) | AST-only | 9 / 9 |
### security — 6 rules
@@ -239,14 +305,26 @@ Known-slow patterns with a faster equivalent. No correctness impact.
| [`use-solid-for-component`](https://biomejs.dev/linter/rules/useSolidForComponent) | AST-only | 2 / 2 |
| [`use-top-level-regex`](https://biomejs.dev/linter/rules/useTopLevelRegex) | AST-only | 2 / 2 |
-### complexity — 17 rules
+### complexity — 52 rules
Needless complication with a simpler equivalent. No correctness or perf impact.
| Rule | Mode | Fixtures |
|---|:-:|---:|
+| [`no-adjacent-spaces-in-regex`](https://biomejs.dev/linter/rules/noAdjacentSpacesInRegex) | AST-only | 31 / 31 |
+| [`no-arguments`](https://biomejs.dev/linter/rules/noArguments) | AST-only | 1 / 1 |
+| [`no-comma-operator`](https://biomejs.dev/linter/rules/noCommaOperator) | AST-only | 29 / 29 |
| [`no-duplicate-type-constituents`](https://typescript-eslint.io/rules/no-duplicate-type-constituents) | type-aware | 82 / 82 |
+| [`no-empty-type-parameters`](https://biomejs.dev/linter/rules/noEmptyTypeParameters) | AST-only | 2 / 2 |
+| [`no-excessive-lines-per-function`](https://biomejs.dev/linter/rules/noExcessiveLinesPerFunction) | AST-only | 1 / 1 |
+| [`no-excessive-nested-test-suites`](https://biomejs.dev/linter/rules/noExcessiveNestedTestSuites) | AST-only | 2 / 2 |
+| [`no-extra-boolean-cast`](https://biomejs.dev/linter/rules/noExtraBooleanCast) | AST-only | 2 / 2 |
+| [`no-flat-map-identity`](https://biomejs.dev/linter/rules/noFlatMapIdentity) | AST-only | 2 / 2 |
+| [`no-for-each`](https://biomejs.dev/linter/rules/noForEach) | AST-only | 2 / 2 |
| [`no-redundant-type-constituents`](https://typescript-eslint.io/rules/no-redundant-type-constituents) | type-aware | 104 / 104 |
+| [`no-restricted-types`](https://biomejs.dev/linter/rules/noRestrictedTypes) | AST-only | — |
+| [`no-static-only-class`](https://biomejs.dev/linter/rules/noStaticOnlyClass) | AST-only | 2 / 2 |
+| [`no-this-in-static`](https://biomejs.dev/linter/rules/noThisInStatic) | AST-only | 2 / 2 |
| [`no-unnecessary-boolean-literal-compare`](https://typescript-eslint.io/rules/no-unnecessary-boolean-literal-compare) | type-aware | 45 / 45 |
| [`no-unnecessary-condition`](https://typescript-eslint.io/rules/no-unnecessary-condition) | type-aware | 296 / 296 |
| [`no-unnecessary-qualifier`](https://typescript-eslint.io/rules/no-unnecessary-qualifier) | type-aware | 17 / 17 |
@@ -255,15 +333,81 @@ Needless complication with a simpler equivalent. No correctness or perf impact.
| [`no-unnecessary-type-assertion`](https://typescript-eslint.io/rules/no-unnecessary-type-assertion) | type-aware | 223 / 223 |
| [`no-unnecessary-type-conversion`](https://typescript-eslint.io/rules/no-unnecessary-type-conversion) | type-aware | 66 / 66 |
| [`no-unnecessary-type-parameters`](https://typescript-eslint.io/rules/no-unnecessary-type-parameters) | type-aware | 160 / 160 |
+| [`no-useless-catch`](https://biomejs.dev/linter/rules/noUselessCatch) | AST-only | 2 / 2 |
+| [`no-useless-catch-binding`](https://biomejs.dev/linter/rules/noUselessCatchBinding) | AST-only | 4 / 4 |
+| [`no-useless-continue`](https://biomejs.dev/linter/rules/noUselessContinue) | AST-only | 2 / 2 |
| [`no-useless-default-assignment`](https://typescript-eslint.io/rules/no-useless-default-assignment) | type-aware | 83 / 83 |
+| [`no-useless-empty-export`](https://biomejs.dev/linter/rules/noUselessEmptyExport) | AST-only | 8 / 8 |
+| [`no-useless-label`](https://biomejs.dev/linter/rules/noUselessLabel) | AST-only | 36 / 36 |
+| [`no-useless-rename`](https://biomejs.dev/linter/rules/noUselessRename) | AST-only | 2 / 2 |
+| [`no-useless-string-concat`](https://biomejs.dev/linter/rules/noUselessStringConcat) | AST-only | 2 / 2 |
+| [`no-useless-string-raw`](https://biomejs.dev/linter/rules/noUselessStringRaw) | AST-only | 2 / 2 |
+| [`no-useless-switch-case`](https://biomejs.dev/linter/rules/noUselessSwitchCase) | AST-only | 2 / 2 |
+| [`no-useless-ternary`](https://biomejs.dev/linter/rules/noUselessTernary) | AST-only | 3 / 3 |
+| [`no-useless-type-constraint`](https://biomejs.dev/linter/rules/noUselessTypeConstraint) | AST-only | 3 / 3 |
+| [`no-useless-undefined-initialization`](https://biomejs.dev/linter/rules/noUselessUndefinedInitialization) | AST-only | 2 / 2 |
+| [`no-void`](https://biomejs.dev/linter/rules/noVoid) | AST-only | 2 / 2 |
| [`non-nullable-type-assertion-style`](https://typescript-eslint.io/rules/non-nullable-type-assertion-style) | type-aware | 20 / 20 |
| [`prefer-destructuring`](https://typescript-eslint.io/rules/prefer-destructuring) | type-aware | 92 / 92 |
| [`prefer-nullish-coalescing`](https://typescript-eslint.io/rules/prefer-nullish-coalescing) | type-aware | 617 / 617 |
| [`prefer-optional-chain`](https://typescript-eslint.io/rules/prefer-optional-chain) | type-aware | 45 / 45 |
| [`prefer-reduce-type-parameter`](https://typescript-eslint.io/rules/prefer-reduce-type-parameter) | type-aware | 31 / 31 |
| [`prefer-return-this-type`](https://typescript-eslint.io/rules/prefer-return-this-type) | type-aware | 21 / 21 |
+| [`use-arrow-function`](https://biomejs.dev/linter/rules/useArrowFunction) | AST-only | 4 / 4 |
+| [`use-date-now`](https://biomejs.dev/linter/rules/useDateNow) | AST-only | 2 / 2 |
+| [`use-flat-map`](https://biomejs.dev/linter/rules/useFlatMap) | AST-only | 10 / 10 |
+| [`use-index-of`](https://biomejs.dev/linter/rules/useIndexOf) | AST-only | 2 / 2 |
+| [`use-literal-keys`](https://biomejs.dev/linter/rules/useLiteralKeys) | AST-only | 4 / 4 |
+| [`use-max-params`](https://biomejs.dev/linter/rules/useMaxParams) | AST-only | 4 / 4 |
+| [`use-numeric-literals`](https://biomejs.dev/linter/rules/useNumericLiterals) | AST-only | 3 / 3 |
+| [`use-simple-number-keys`](https://biomejs.dev/linter/rules/useSimpleNumberKeys) | AST-only | 2 / 2 |
+| [`use-simplified-logic-expression`](https://biomejs.dev/linter/rules/useSimplifiedLogicExpression) | AST-only | 2 / 2 |
+| [`use-while`](https://biomejs.dev/linter/rules/useWhile) | AST-only | 2 / 2 |
-### style — 7 rules
+### a11y — 36 rules
+
+JSX patterns that break screen readers, keyboard navigation, or assistive tech. Mirrors biome's a11y category and jsx-a11y/eslint-plugin-jsx-a11y.
+
+| Rule | Mode | Fixtures |
+|---|:-:|---:|
+| [`no-access-key`](https://biomejs.dev/linter/rules/noAccessKey) | AST-only | 2 / 2 |
+| [`no-aria-hidden-on-focusable`](https://biomejs.dev/linter/rules/noAriaHiddenOnFocusable) | AST-only | 2 / 2 |
+| [`no-aria-unsupported-elements`](https://biomejs.dev/linter/rules/noAriaUnsupportedElements) | AST-only | 2 / 2 |
+| [`no-autofocus`](https://biomejs.dev/linter/rules/noAutofocus) | AST-only | 2 / 2 |
+| [`no-distracting-elements`](https://biomejs.dev/linter/rules/noDistractingElements) | AST-only | 1 / 1 |
+| [`no-header-scope`](https://biomejs.dev/linter/rules/noHeaderScope) | AST-only | 2 / 2 |
+| [`no-interactive-element-to-noninteractive-role`](https://biomejs.dev/linter/rules/noInteractiveElementToNoninteractiveRole) | AST-only | 2 / 2 |
+| [`no-label-without-control`](https://biomejs.dev/linter/rules/noLabelWithoutControl) | AST-only | 2 / 2 |
+| [`no-noninteractive-element-interactions`](https://biomejs.dev/linter/rules/noNoninteractiveElementInteractions) | AST-only | 2 / 2 |
+| [`no-noninteractive-element-to-interactive-role`](https://biomejs.dev/linter/rules/noNoninteractiveElementToInteractiveRole) | AST-only | 2 / 2 |
+| [`no-noninteractive-tabindex`](https://biomejs.dev/linter/rules/noNoninteractiveTabindex) | AST-only | 2 / 2 |
+| [`no-positive-tabindex`](https://biomejs.dev/linter/rules/noPositiveTabindex) | AST-only | 4 / 4 |
+| [`no-redundant-alt`](https://biomejs.dev/linter/rules/noRedundantAlt) | AST-only | 2 / 2 |
+| [`no-redundant-roles`](https://biomejs.dev/linter/rules/noRedundantRoles) | AST-only | 3 / 3 |
+| [`no-static-element-interactions`](https://biomejs.dev/linter/rules/noStaticElementInteractions) | AST-only | 2 / 2 |
+| [`no-svg-without-title`](https://biomejs.dev/linter/rules/noSvgWithoutTitle) | AST-only | 2 / 2 |
+| [`use-alt-text`](https://biomejs.dev/linter/rules/useAltText) | AST-only | 3 / 3 |
+| [`use-anchor-content`](https://biomejs.dev/linter/rules/useAnchorContent) | AST-only | 2 / 2 |
+| [`use-aria-activedescendant-with-tabindex`](https://biomejs.dev/linter/rules/useAriaActivedescendantWithTabindex) | AST-only | 2 / 2 |
+| [`use-aria-props-for-role`](https://biomejs.dev/linter/rules/useAriaPropsForRole) | AST-only | 2 / 2 |
+| [`use-aria-props-supported-by-role`](https://biomejs.dev/linter/rules/useAriaPropsSupportedByRole) | AST-only | 3 / 3 |
+| [`use-button-type`](https://biomejs.dev/linter/rules/useButtonType) | AST-only | 0 / 0 |
+| [`use-focusable-interactive`](https://biomejs.dev/linter/rules/useFocusableInteractive) | AST-only | 2 / 2 |
+| [`use-heading-content`](https://biomejs.dev/linter/rules/useHeadingContent) | AST-only | 2 / 2 |
+| [`use-html-lang`](https://biomejs.dev/linter/rules/useHtmlLang) | AST-only | 2 / 2 |
+| [`use-iframe-title`](https://biomejs.dev/linter/rules/useIframeTitle) | AST-only | 2 / 2 |
+| [`use-key-with-click-events`](https://biomejs.dev/linter/rules/useKeyWithClickEvents) | AST-only | 2 / 2 |
+| [`use-key-with-mouse-events`](https://biomejs.dev/linter/rules/useKeyWithMouseEvents) | AST-only | 2 / 2 |
+| [`use-media-caption`](https://biomejs.dev/linter/rules/useMediaCaption) | AST-only | 2 / 2 |
+| [`use-semantic-elements`](https://biomejs.dev/linter/rules/useSemanticElements) | AST-only | 3 / 3 |
+| [`use-valid-anchor`](https://biomejs.dev/linter/rules/useValidAnchor) | AST-only | 2 / 2 |
+| [`use-valid-aria-props`](https://biomejs.dev/linter/rules/useValidAriaProps) | AST-only | 2 / 2 |
+| [`use-valid-aria-role`](https://biomejs.dev/linter/rules/useValidAriaRole) | AST-only | 2 / 2 |
+| [`use-valid-aria-values`](https://biomejs.dev/linter/rules/useValidAriaValues) | AST-only | 2 / 2 |
+| [`use-valid-autocomplete`](https://biomejs.dev/linter/rules/useValidAutocomplete) | AST-only | 0 / 0 |
+| [`use-valid-lang`](https://biomejs.dev/linter/rules/useValidLang) | AST-only | 2 / 2 |
+
+### style — 61 rules
Formatting, naming, ordering. Pure preference; team-configurable.
@@ -272,10 +416,64 @@ Formatting, naming, ordering. Pure preference; team-configurable.
| [`consistent-type-exports`](https://typescript-eslint.io/rules/consistent-type-exports) | type-aware | 47 / 47 |
| [`dot-notation`](https://typescript-eslint.io/rules/dot-notation) | type-aware | 61 / 61 |
| [`naming-convention`](https://typescript-eslint.io/rules/naming-convention) | type-aware | 88 / 88 |
+| [`no-common-js`](https://biomejs.dev/linter/rules/noCommonJs) | AST-only | 2 / 2 |
+| [`no-default-export`](https://biomejs.dev/linter/rules/noDefaultExport) | AST-only | 13 / 13 |
+| [`no-done-callback`](https://biomejs.dev/linter/rules/noDoneCallback) | AST-only | 2 / 2 |
| [`no-duplicate-imports`](https://eslint.org/docs/latest/rules/no-duplicate-imports) | AST-only | 86 / 86 |
+| [`no-enum`](https://biomejs.dev/linter/rules/noEnum) | AST-only | 2 / 2 |
+| [`no-exported-imports`](https://biomejs.dev/linter/rules/noExportedImports) | AST-only | 2 / 2 |
+| [`no-head-element`](https://biomejs.dev/linter/rules/noHeadElement) | AST-only | — |
+| [`no-implicit-boolean`](https://biomejs.dev/linter/rules/noImplicitBoolean) | AST-only | 2 / 2 |
| [`no-meaningless-void-operator`](https://typescript-eslint.io/rules/no-meaningless-void-operator) | type-aware | 5 / 5 |
+| [`no-namespace`](https://biomejs.dev/linter/rules/noNamespace) | AST-only | 2 / 2 |
+| [`no-negation-else`](https://biomejs.dev/linter/rules/noNegationElse) | AST-only | 3 / 3 |
+| [`no-nested-ternary`](https://biomejs.dev/linter/rules/noNestedTernary) | AST-only | 2 / 2 |
+| [`no-non-null-assertion`](https://biomejs.dev/linter/rules/noNonNullAssertion) | AST-only | 2 / 2 |
+| [`no-parameter-assign`](https://biomejs.dev/linter/rules/noParameterAssign) | AST-only | 68 / 68 |
+| [`no-parameter-properties`](https://biomejs.dev/linter/rules/noParameterProperties) | AST-only | 2 / 2 |
+| [`no-process-env`](https://biomejs.dev/linter/rules/noProcessEnv) | AST-only | 6 / 6 |
+| [`no-restricted-globals`](https://biomejs.dev/linter/rules/noRestrictedGlobals) | AST-only | 3 / 3 |
+| [`no-restricted-imports`](https://biomejs.dev/linter/rules/noRestrictedImports) | AST-only | — |
+| [`no-shouty-constants`](https://biomejs.dev/linter/rules/noShoutyConstants) | AST-only | 2 / 2 |
+| [`no-substr`](https://biomejs.dev/linter/rules/noSubstr) | AST-only | 2 / 2 |
+| [`no-unused-template-literal`](https://biomejs.dev/linter/rules/noUnusedTemplateLiteral) | AST-only | 2 / 2 |
+| [`no-useless-else`](https://biomejs.dev/linter/rules/noUselessElse) | AST-only | 3 / 3 |
+| [`no-yoda-expression`](https://biomejs.dev/linter/rules/noYodaExpression) | AST-only | 4 / 4 |
| [`prefer-readonly`](https://typescript-eslint.io/rules/prefer-readonly) | type-aware | 162 / 162 |
| [`prefer-readonly-parameter-types`](https://typescript-eslint.io/rules/prefer-readonly-parameter-types) | type-aware | 130 / 130 |
+| [`use-array-literals`](https://biomejs.dev/linter/rules/useArrayLiterals) | AST-only | 4 / 4 |
+| [`use-as-const-assertion`](https://biomejs.dev/linter/rules/useAsConstAssertion) | AST-only | 2 / 2 |
+| [`use-block-statements`](https://biomejs.dev/linter/rules/useBlockStatements) | AST-only | 1 / 1 |
+| [`use-collapsed-else-if`](https://biomejs.dev/linter/rules/useCollapsedElseIf) | AST-only | 2 / 2 |
+| [`use-collapsed-if`](https://biomejs.dev/linter/rules/useCollapsedIf) | AST-only | 2 / 2 |
+| [`use-consistent-array-type`](https://biomejs.dev/linter/rules/useConsistentArrayType) | AST-only | 2 / 2 |
+| [`use-consistent-arrow-return`](https://biomejs.dev/linter/rules/useConsistentArrowReturn) | AST-only | 2 / 2 |
+| [`use-consistent-builtin-instantiation`](https://biomejs.dev/linter/rules/useConsistentBuiltinInstantiation) | AST-only | 2 / 2 |
+| [`use-consistent-member-accessibility`](https://biomejs.dev/linter/rules/useConsistentMemberAccessibility) | AST-only | — |
+| [`use-consistent-object-definitions`](https://biomejs.dev/linter/rules/useConsistentObjectDefinitions) | AST-only | — |
+| [`use-consistent-type-definitions`](https://biomejs.dev/linter/rules/useConsistentTypeDefinitions) | AST-only | 2 / 2 |
+| [`use-default-parameter-last`](https://biomejs.dev/linter/rules/useDefaultParameterLast) | AST-only | 4 / 4 |
+| [`use-enum-initializers`](https://biomejs.dev/linter/rules/useEnumInitializers) | AST-only | 2 / 2 |
+| [`use-explicit-length-check`](https://biomejs.dev/linter/rules/useExplicitLengthCheck) | AST-only | 2 / 2 |
+| [`use-exponentiation-operator`](https://biomejs.dev/linter/rules/useExponentiationOperator) | AST-only | 12 / 12 |
+| [`use-exports-last`](https://biomejs.dev/linter/rules/useExportsLast) | AST-only | 14 / 14 |
+| [`use-for-of`](https://biomejs.dev/linter/rules/useForOf) | AST-only | 2 / 2 |
+| [`use-fragment-syntax`](https://biomejs.dev/linter/rules/useFragmentSyntax) | AST-only | 2 / 2 |
+| [`use-grouped-accessor-pairs`](https://biomejs.dev/linter/rules/useGroupedAccessorPairs) | AST-only | 2 / 2 |
+| [`use-node-assert-strict`](https://biomejs.dev/linter/rules/useNodeAssertStrict) | AST-only | 3 / 3 |
+| [`use-nodejs-import-protocol`](https://biomejs.dev/linter/rules/useNodejsImportProtocol) | AST-only | 3 / 3 |
+| [`use-number-namespace`](https://biomejs.dev/linter/rules/useNumberNamespace) | AST-only | 3 / 3 |
+| [`use-numeric-separators`](https://biomejs.dev/linter/rules/useNumericSeparators) | AST-only | 2 / 2 |
+| [`use-object-spread`](https://biomejs.dev/linter/rules/useObjectSpread) | AST-only | 5 / 5 |
+| [`use-react-function-components`](https://biomejs.dev/linter/rules/useReactFunctionComponents) | AST-only | 2 / 2 |
+| [`use-self-closing-elements`](https://biomejs.dev/linter/rules/useSelfClosingElements) | AST-only | 2 / 2 |
+| [`use-shorthand-assign`](https://biomejs.dev/linter/rules/useShorthandAssign) | AST-only | 2 / 2 |
+| [`use-shorthand-function-type`](https://biomejs.dev/linter/rules/useShorthandFunctionType) | AST-only | 2 / 2 |
+| [`use-single-var-declarator`](https://biomejs.dev/linter/rules/useSingleVarDeclarator) | AST-only | 2 / 2 |
+| [`use-symbol-description`](https://biomejs.dev/linter/rules/useSymbolDescription) | AST-only | 2 / 2 |
+| [`use-throw-new-error`](https://biomejs.dev/linter/rules/useThrowNewError) | AST-only | 2 / 2 |
+| [`use-throw-only-error`](https://biomejs.dev/linter/rules/useThrowOnlyError) | AST-only | 2 / 2 |
+| [`use-trim-start-end`](https://biomejs.dev/linter/rules/useTrimStartEnd) | AST-only | 2 / 2 |
### nursery — 0 rules
@@ -296,7 +494,7 @@ go test -count=1 -run EslintCompatibility -v \
./internal/rules//
```
-The aggregate validates all 182 rules against **10669 cases** in one
+The aggregate validates all 373 rules against **11723 cases** in one
go. See [`docs/OXLINT-COMPAT-OVERVIEW.md`](https://github.com/jetlint/jetlint/blob/main/docs/OXLINT-COMPAT-OVERVIEW.md)
for the AST-only fixture format and how to regenerate from a fresh
oxc/biome checkout.