@lint-suite/oxlint-config
v1.0.3
Published
Oxlint configuration presets mirroring the lint-suite ESLint presets
Readme
@lint-suite/oxlint-config
Oxlint configuration presets mirroring the lint-suite ESLint presets. Rules oxlint can't run are listed in MISSING.md.
Install
pnpm add -D @lint-suite/oxlint-config oxlintPeers: oxlint >=1.88.0, typescript, and eslint. eslint is required even if you only run oxlint: the JS plugins load @typescript-eslint/utils, which imports it at runtime. oxlint-tsgolint is optional (see below).
Use defineLintSuiteConfig
Create oxlint.config.ts:
import {
defineLintSuiteConfig,
recommended,
angular,
vitest
} from '@lint-suite/oxlint-config';
export default defineLintSuiteConfig(recommended, angular, vitest, {
rules: { 'eslint/no-console': 'warn' }
});Always compose with defineLintSuiteConfig. Oxlint ignores settings, globals, env and ignorePatterns at the top level of an extended config. A plain { extends: [recommended] } silently loses them, and boundaries then reports nothing. The helper hoists them to the root, later configs win, and your own config goes last.
.oxlintrc.json is not supported: its extends only takes file paths.
In a package without "type": "module", Node prints a MODULE_TYPELESS_PACKAGE_JSON warning every time it loads oxlint.config.ts. Name the file oxlint.config.mts there and pass it with oxlint -c oxlint.config.mts.
Exports are layers of recommended
recommended is base, javascript, typescript and boundaries together. Each export is one layer of it, not a standalone preset.
typescriptalone lacks the shared core rules (for-direction,no-cond-assignand the rest of the ESLint recommended set). They live injavascript.javascriptalone applies those shared core rules to TypeScript files too, not only to JavaScript files.
Add the layers you need next to each other, or start from recommended.
| Export | Contents |
| ----------------------- | ----------------------------------------------------------------- |
| recommended | base, javascript, typescript, boundaries |
| base | Practices, limits and stylistic rules for JS and TS files |
| javascript | ESLint core rules |
| typescript | Type-free TypeScript rules, import rules, local plugin rules |
| boundaries | boundaries and modular-boundaries rules with their settings |
| typescriptTypeAware | The 27 type-aware typescript/* rules. Add next to recommended |
| angular | Angular rules (opt-in) |
| rxjs | The 5 type-free rxjs rules (opt-in) |
| vitest | Vitest rules (opt-in) |
| playwright | Playwright rules (opt-in) |
| storybook | Storybook rules (opt-in) |
| defineLintSuiteConfig | Helper that composes the configs above |
Subpaths: @lint-suite/oxlint-config/local-plugin (the local JS plugin), @lint-suite/oxlint-config/eslint (oxlintOverlap) and @lint-suite/oxlint-config/eslint-missing (ESLint presets for the rules oxlint does not run).
Type-aware rules
typescriptTypeAware needs oxlint-tsgolint (optional peer). Its bundled engine is a native typescript-go build that targets TypeScript 7, so you don't install TypeScript 7 yourself. It ran here once, by hand, on this repo (TypeScript 6) and reported typescript(no-unsafe-call) and typescript(require-await). CI does not run it, and rule options are only checked as config. prefer-optional-chain and no-unnecessary-condition are in oxlint's nursery category and may not run or may change.
ESLint presets for the rules oxlint does not run: eslint-missing
An oxlint preset plus the eslint-missing preset of the same name gives you the lint-suite ESLint preset, with no rule run twice.
// eslint.config.ts
import {
recommended,
angular,
angularTemplate
} from '@lint-suite/oxlint-config/eslint-missing';
export default [...recommended, ...angular, ...angularTemplate];
// oxlint.config.ts
import {
recommended,
angular,
defineLintSuiteConfig
} from '@lint-suite/oxlint-config';
export default defineLintSuiteConfig(recommended, angular);It needs lint-suite installed (optional peer ^3.0.0).
Exports:
recommended,angular,rxjs,vitest,playwrightandstorybookhold thelint-suite/eslintpreset of the same name, with the rules the same-named oxlint preset runs turned off.angularTemplate,jsonandprettierare the same as inlint-suite/eslint. oxlint does not lint.htmlor.jsonfiles, andprettieronly turns rules off.
There are no layer exports (base, javascript, typescript, boundaries). lint-suite and oxlint split rules across layers differently, so one mirrored layer would turn back on rules that oxlint already runs. Start from recommended.
If you customise the oxlint config (own overrides, ignorePatterns, rules turned off, typescriptTypeAware), use the lint-suite/eslint presets with oxlintOverlap(yourConfig) instead. See the next section. The oxlintOverlap limits listed there (.gitignore, .eslintignore, rule options, config location) apply to eslint-missing too.
Turn off overlap in ESLint: oxlintOverlap
If you run ESLint next to oxlint, append oxlintOverlap(config) to your ESLint flat config. It turns off, in ESLint, every rule that the oxlint config enables, JS-plugin rules included, but only for the files oxlint lints with that rule:
import { recommended } from 'lint-suite/eslint';
import { oxlintOverlap } from '@lint-suite/oxlint-config/eslint';
import oxlintConfig from './oxlint.config.ts';
export default [...recommended, ...oxlintOverlap(oxlintConfig)];How the blocks are scoped:
- Top-level rules are turned off only for the file types oxlint lints (
.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts). ESLint keeps them on for.html,.jsonand the rest. - Rules enabled by an override are turned off only for files that match both that override's
filesand an oxlint file type. A glob that can match other files, such asscripts/**, is paired with each oxlint extension glob as an ESLint nestedfilesentry ([['scripts/**', '**/*.ts'], …]), so ESLint keeps the rule on forscripts/a.htmlandscripts/a.json. - If a later override turns a rule off for some paths, the ESLint block gets those paths as
ignores, so ESLint still lints them. - Rule keys are read as oxlint reads them:
@typescript-eslint/x,import-x/x,react-hooks/xand the other aliases oxlint accepts count as the rule they stand for, andtypescript/default-param-lastturns offeslint/default-param-last. - A built-in rule counts only when oxlint runs its plugin:
eslintalways, plus everypluginslist in your config and itsextends(a config withoutpluginsmeansunicorn,typescript,oxc). An override's ownpluginscount only for that override's rules and files, as in oxlint. Exception: whenimportis enabled only inside an override, oxlint builds no module graph, soimport/default,export,named,namespace,no-cycle,no-named-as-default,no-named-as-default-memberandno-self-importdo not run there, and ESLint keeps them on. - Files matched by the root
ignorePatternsare ignored by every block, so ESLint keeps every rule on for them. - oxlint never lints minified files, even when you pass them by path: any file whose name contains
.min.,-min.or_min., such asvendor/lib.min.jsorsrc/a-min.ts. The match is case-sensitive and looks at the file name only, soa.MIN.jsanda.min/b.jsare linted. Every block ignores minified files, even ones a negatedignorePatternsentry re-includes, so ESLint keeps every rule on for them.
Limits:
- oxlint also skips files in
.gitignore;oxlintOverlapdoes not read it. If ESLint should skip them too, addincludeIgnoreFilefrom@eslint/compatto your ESLint config. - oxlint also skips the paths listed in
.eslintignore(it reads that file by default);oxlintOverlapdoes not read it either. ESLint flat config ignores.eslintignore, so the rules turned off there run in neither tool. Add those paths to your ESLintignorestoo, or remove them from.eslintignore. - Rule options set in the ESLint config are not carried over.
oxlintOverlapturns the ESLint rule off, so an option override, such asmaxLineLengthforlocal/one-line-guard, must be repeated in the oxlint config. Otherwise oxlint runs the rule with the preset's options. - oxlint lints the
<script>blocks of.vue,.svelteand.astrofiles, butoxlintOverlapleaves those files to ESLint with every rule on. - A bare glob (no
/) in an oxlint override is emitted as**/<pattern>, because oxlint matches it at any depth and ESLint only at the top level. excludeFilesis not supported and throws.oxlintOverlapreads the oxlint config'signorePatternsand overridefilesglobs as relative to the same base directory as the ESLint config, so keep.oxlintrc.json/oxlint.config.tsnext toeslint.config.*.- A bare rule name such as
'no-null'is not supported and throws, naming the key and where it is (rules,overrides[0].rules,extends[1].rules, …): oxlint picks its plugin from an internal registry. Write it with its prefix, e.g.'unicorn/no-null'.
Missing rules
See MISSING.md for every ESLint rule that is not ported, and why.
