@utoo/lint
v0.4.7
Published
High-performance JavaScript and TypeScript linter powered by Yuku
Readme
@utoo/lint
A high-performance linter for JavaScript and TypeScript, written in Zig and powered by Yuku.
@utoo/lint combines a native lint engine with familiar configuration, CLI,
and JavaScript APIs.
Installation · Quick start · Rules · Configuration · GitHub
Why utoo-lint?
- Native performance — Zig and Yuku power parsing, semantic analysis, and parallel file linting.
- Broad rule coverage — More than 300 rules cover JavaScript, TypeScript, React, JSX accessibility, and imports.
- ESLint plugin compatibility — Mount community ESLint plugins in
utlint.config.ts; their rules run alongside native rules with shared suppressions, autofix, and reporting. - Familiar configuration — Use typed
utlint.config.tsor staticutlint.config.json, with ESLint-style rule names and severities. - Practical workflows — Safe autofix, suppression comments, JSON output, and ESM/CommonJS APIs are included.
- Portable installation — Prebuilt binaries are available for macOS, Linux, and Windows on supported architectures.
Installation
@utoo/lint requires Node.js 20 or later.
utoo
utoo is a fast, npm-compatible package manager written in Rust. Install it once if it is not already available:
npm install -g utooAdd @utoo/lint as a development dependency:
ut install @utoo/lint -DIn an existing project, run ut install without a package name to install all
dependencies declared in package.json.
Other package managers
pnpm add -D @utoo/lint
npm install --save-dev @utoo/lintThe package selects the native binary for the current platform. No Zig toolchain is required.
Quick start
Run with the default rules
utx @utoo/lint srcWithout a config file, utoo-lint uses its built-in default rules. It supports
.js, .jsx, .ts, .tsx, .mjs, .cjs, .mts, and .cts files.
Add a typed config
Create utlint.config.ts:
import { defineConfig } from "@utoo/lint/config";
import frontend from "@utoo/lint/configs/frontend";
export default defineConfig({
...frontend,
ignores: [...frontend.ignores, ".next", "storybook-static"],
rules: {
...frontend.rules,
"no-console": "off",
"react/no-forward-ref": "off"
}
});The frontend preset uses error for correctness and safety checks that should
fail CI, and warn for migration or maintainability checks that should remain
visible without blocking adoption:
| Severity | Added frontend guardrails |
| --- | --- |
| error | react-hooks/rules-of-hooks, react/jsx-key, react/no-children-prop, react/no-danger-with-children, react/void-dom-elements-no-children, no-script-url, promise/no-nesting |
| warn | react-hooks/exhaustive-deps, react/no-array-index-key, react/no-unstable-nested-components, react/no-forward-ref, unused-imports/no-unused-imports, @typescript-eslint/no-unused-vars, @typescript-eslint/ban-types |
Override project-specific rules after spreading frontend.rules, and append
framework-generated directories to frontend.ignores, as shown above.
The preset intentionally enables no formatter or type-checker integration.
Keep Prettier (or another formatter) and tsc as independent project steps.
The CLI discovers the config and uses its files patterns:
utx @utoo/lintSee the configuration guide for flat config arrays, global ignores, rule options, and config precedence.
Add package scripts
{
"scripts": {
"lint": "utoo-lint src",
"lint:fix": "utoo-lint --fix src"
}
}With utoo, run these scripts as ut lint and ut lint:fix.
Common commands
| Task | Command |
| --- | --- |
| Lint files | utx @utoo/lint src |
| Apply safe fixes | utx @utoo/lint --fix src |
| Preview fixes as JSON | utx @utoo/lint --fix-dry-run --format=json src |
| Select rules for one run | utx @utoo/lint --rules=no-debugger,no-unused-vars src |
| Use an explicit config | utx @utoo/lint --config=utlint.config.json src |
Run utx @utoo/lint --help for all CLI options. Once the package is installed,
utlint is a shorter alias for the utoo-lint command.
Configuration
utoo-lint supports two canonical config formats. They are alternative
representations of one active config and are not merged together.
| Config | Best for | Raw native binary |
| --- | --- | --- |
| utlint.config.ts | Typed authoring, imports, presets, and computed values | No |
| utlint.config.json | Static configuration and JSON Schema validation | Yes |
Rule severities follow ESLint conventions: off, warn, error, 0, 1,
and 2. A selected config enables only the rules present in its resolved
rules map.
The npm CLI and JavaScript API load both formats. The raw native binary loads JSON only. See the configuration guide for the complete behavior.
Autofix
Apply safe fixes in place:
utx @utoo/lint --fix srcPreview fixes without writing files:
utx @utoo/lint --fix-dry-run --format=json srcFixes run until the source is stable, subject to a safety pass limit. The rule status documents autofix support for each rule.
Suppression comments
Use suppression comments for intentional exceptions without disabling a rule in project configuration:
// utlint-ignore no-debugger: generated breakpoint
debugger;| Directive | Scope |
| --- | --- |
| utlint-ignore [rule] | The next line of code |
| utlint-ignore-all [rule] | The entire file when placed before any code |
| utlint-ignore-start [rule] | The start of a suppressed range |
| utlint-ignore-end [rule] | The end of a suppressed range |
A directive may target one rule ID. Omitting it creates or closes an all-rules suppression. Parse errors are never suppressed, and suppressed fixes are not applied.
See the suppression comments guide for range examples and API behavior.
Migrating from ESLint
Convert an existing ESLint config into a native utoo-lint config:
utx @utoo/lint migrate eslint \
--from eslint.config.js \
--output utlint.config.jsonThe package registers only the utoo-lint and utlint commands. For
incremental replacement workflows it also ships an ESLint CLI wrapper at
@utoo/lint/bin/eslint.js and a fishlint compatibility CLI at
@utoo/lint/bin/fishlint.js. Neither is registered as a bin, so installing
@utoo/lint never changes what existing eslint or fishlint scripts run;
opt in per script instead. See the
migration guide
for supported mappings and known differences.
JavaScript API
The package provides ESM and CommonJS entry points:
import { lintFiles } from "@utoo/lint";
const report = lintFiles(["src"], {
config: "utlint.config.ts"
});
console.log(report.diagnostics);An ESLint-style API is also available:
import { ESLint } from "@utoo/lint";
const eslint = new ESLint({ fix: true });
const results = await eslint.lintFiles(["src"]);
await ESLint.outputFixes(results);await eslint.loadFormatter() and cliEngine.getFormatter() default to an
ESLint-style stylish report: aligned columns, blank lines between files,
diagnostics sorted by line and column, and a summary of fixable errors and
warnings. Rule messages (including punctuation), result arrays, and exit codes
are unchanged. Only actual autofixes count toward the --fix hint, not editor
suggestions; missing JSX keys still need a manually chosen stable, unique key.
The stylish formatter detects color support on stdout. Pass color: true or
color: false to the ESLint or CLIEngine constructor to override detection.
Otherwise, NO_COLOR or NODE_DISABLE_COLORS disables color; FORCE_COLOR
forces it (0 disables), followed by CLICOLOR_FORCE and stdout TTY detection
(TERM=dumb disables automatic color). Constructor env overrides also apply.
JSON, JSON-with-metadata, compact, unix, and native CLI text formats are unchanged.
Raw reports include active diagnostics, suppressed diagnostics, fixed outputs,
and an exit code. The compatibility layer also exports Linter, CLIEngine,
RuleTester, and SourceCode APIs.
Native JSON diagnostics and ESLint-compatible messages include one-based line,
column, endLine, and endColumn positions for source spans. Columns count
UTF-16 code units, and the end position is exclusive. Suppressed diagnostics keep
the same range. I/O errors without a source span omit the end positions; messages
from older native binaries may also omit them.
ESLint and CLIEngine also discover classic .eslintrc.* files (or
eslintConfig in package.json) when no native config applies. Legacy
extends, directory cascades, root, overrides, and ignore patterns are
resolved per source filename. Precedence is baseConfig, project config,
then overrideConfig; useEslintrc: false disables discovery. Native config
files still take priority. The lower-level lintFiles, lintText, and native
CLI keep their native-only discovery behavior.
Legacy configuration resolution uses @eslint/eslintrc. If the project has
ESLint 8 installed, its configuration resolver is used instead to support
shared configs that patch ESLint's module resolution. Neither path uses ESLint
to parse or lint source files: rules still run in utoo-lint. Enabled rules that
utoo-lint does not support remain errors, not silently skipped checks.
The Node wrapper captures up to 64 MiB from each native stdout and stderr
stream by default. Programmatic run, runCli, and runFishlint calls can set
maxBuffer to another positive byte count. Set UTOO_LINT_MAX_BUFFER to apply
the same limit to CLI invocations; output beyond the configured bound reports
ENOBUFS instead of being truncated.
WebAssembly
For browser playgrounds and in-memory Node ESM usage, install the independent
@utoo/lint-wasm package. It ships a freestanding WebAssembly module rather
than selecting one of the native platform packages used by @utoo/lint.
See the WebAssembly guide for its API, runtime boundaries, and Web Worker recommendation.
Supported platforms
The package installs a platform-specific optional dependency containing the native binary.
| Operating system | Architectures | | --- | --- | | macOS | arm64, x64 | | Linux | arm64, x64 | | Windows | x64 |
Set UTOO_LINT_BIN=/path/to/utoo-lint to use a custom binary during local
development.
Documentation
- Rule status
- Configuration
- Suppression comments
- WebAssembly
- Migrating from ESLint
- Benchmarks
- Security policy
