rintenki
v0.14.5
Published
A fast HTML linter powered by html5ever + napi-rs
Maintainers
Readme
rintenki
A fast HTML linter powered by html5ever + napi-rs.
The name "rintenki" comes from the Japanese word "輪転機" (rintenki), meaning a rotary printing press. Like a rotary press that rapidly inspects and produces printed pages, rintenki quickly scans and checks your HTML.
Features
- 103 built-in rules based on the HTML Living Standard
- Rust-powered parsing via html5ever with Node.js bindings
- CLI with
--fix,--watch,--format json/sarif - VS Code extension with real-time linting, Quick Fix, and status bar
- LSP server for editor integration
- Vue / JSX / eRuby / Astro support via parser plugins
- Per-rule severity customization and inline disable comments
- JSON Schema for
.rintenkirc.jsoneditor completion
Install
npm install rintenkiUsage
npx rintenki "src/**/*.html"
npx rintenki --fix "src/**/*.html"
npx rintenki --format json "src/**/*.html"
npx rintenki --watch "src/**/*.html"Options
rintenki [options] <files...>
-c, --config <path> Path to config file (default: .rintenkirc.json)
-f, --format <format> Output format: stylish (default), json, sarif
--fix Auto-fix fixable rules
-w, --watch Watch files for changes and re-lint
--max-warnings <number> Exit with error if warnings exceed this number
-h, --help Show helpAPI
const { lint, fix } = require("rintenki");
const result = lint("<html><body><img></body></html>");
console.log(result.diagnostics);
const fixed = fix('<DIV Class="foo">text</DIV>');
console.log(fixed.output); // <div class="foo">text</div>Configuration
Place .rintenkirc.json in your project root:
{
"rules": {
"doctype": "error",
"no-consecutive-br": "warning",
"no-hard-code-id": "off"
},
"ignore": ["dist/**", "vendor/**"]
}| Value | Description |
|-------|-------------|
| "error" | Report as error (exit code 1) |
| "warning" / "warn" | Report as warning |
| "off" / false | Disable the rule |
| true | Use default severity |
Ignore Patterns
Use a .rintenkiignore file or the ignore field in config. node_modules is always excluded.
Inline Disable Comments
<!-- rintenki-disable-next-line required-attr -->
<img src="photo.jpg">
<img src="photo.jpg"> <!-- rintenki-disable-line -->Parser Plugins
| Plugin | Syntax | Install |
|--------|--------|---------|
| @rintenki/vue-parser | Vue SFC (.vue) | npm i @rintenki/vue-parser |
| @rintenki/jsx-parser | JSX/TSX (.jsx, .tsx) | npm i @rintenki/jsx-parser |
| @rintenki/erb-parser | eRuby (.erb) | npm i @rintenki/erb-parser |
| @rintenki/astro-parser | Astro (.astro) | npm i @rintenki/astro-parser |
Parsers are auto-detected from installed packages, or configured explicitly:
{
"parser": {
".vue": "@rintenki/vue-parser"
}
}Rules
103 rules across 5 categories. Rules marked with a wrench (🔧) are auto-fixable with --fix.
Conformance Checking
| Rule | Default | Description |
|------|---------|-------------|
| attr-duplication | error | Detect duplicate attributes |
| attr-value-quotes 🔧 | warning | Detect unquoted attribute values |
| colspan-rowspan-range | error | Validate colspan (1-1000) and rowspan (0-65534) ranges |
| dfn-no-dfn-descendants | error | Disallow dfn nested inside another dfn |
| deprecated-attr | error | Detect deprecated attributes |
| deprecated-element | error | Detect deprecated elements |
| disallowed-element | off | Detect disallowed elements |
| doctype 🔧 | error | Require DOCTYPE declaration |
| empty-title | error | Detect empty title element |
| end-tag | warning | Detect missing end tags |
| figcaption-position | warning | Require figcaption as first or last child of figure |
| form-dup-name | warning | Detect duplicate form control names |
| header-footer-nesting | error | Detect header/footer/main nesting inside header or footer |
| heading-levels | error | Detect skipped heading levels |
| id-duplication | error | Detect duplicate id values |
| input-attr-applicability | warning | Detect attributes that don't apply to the input type |
| invalid-attr | error | Detect attributes not in the spec |
| link-constraints | error | Validate link element attribute constraints |
| meta-constraints | error | Validate meta element attribute constraints |
| no-empty-track-label | warning | Disallow empty label on track elements |
| no-duplicate-base | error | Detect multiple base or title elements |
| no-duplicate-dt | error | Detect duplicate dt names in dl |
| no-duplicate-in-head | error | Detect duplicate charset/viewport/description meta |
| no-empty-palpable-content | warning | Detect empty palpable content elements |
| no-implicit-button-type | warning | Require explicit type on button |
| no-autoplay-media | warning | Detect autoplay without muted on video/audio |
| no-nested-forms | error | Detect nested form elements |
| no-nested-interactive | error | Detect interactive content inside a or button |
| no-non-scalable-viewport | error | Detect user-scalable=no in viewport meta |
| no-orphaned-end-tag | error | Detect unmatched closing tags |
| no-tabindex-on-dialog | error | Detect tabindex on dialog elements |
| obsolete-but-conforming | warning | Detect obsolete but conforming features |
| permitted-contents | error | Detect children not permitted by the spec |
| picture-structure | error | Validate picture element structure |
| placeholder-label-option | warning | Detect missing placeholder option in required select |
| require-datetime | error | Require datetime attribute on time element |
| require-meta-charset | off | Require meta charset declaration |
| required-attr | error | Detect missing required attributes |
| required-element | error | Detect missing required child elements |
| script-type | error | Validate script type attribute values |
| src-not-empty | error | Detect empty src or href attributes |
| summary-first-child | error | Require summary as first child of details |
| th-content-restrictions | error | Detect disallowed elements inside th |
| unique-main | error | Require at most one visible main element |
| valid-attr-value | error | Validate enumerated attribute values |
| valid-autocomplete | warning | Validate autocomplete attribute values |
| valid-id | error | Require valid id values (non-empty, no whitespace) |
| valid-rel | error | Validate rel attribute values |
| track-has-srclang | error | Require srclang on subtitles track |
| void-content | error | Detect content inside void elements |
| no-duplicate-track | error | Detect duplicate track elements with same kind/srclang/label |
| no-multiple-default-track | error | Detect multiple default tracks in the same category |
| base-before-urls | warning | Require base href before elements with URL attributes |
| address-content-model | error | Detect heading/sectioning/header/footer inside address |
| link-rel-or-itemprop | error | Require rel or itemprop on link elements |
| base-has-href-or-target | error | Require href or target on base element |
Accessibility
| Rule | Default | Description |
|------|---------|-------------|
| aria-attr-conflicts | error | Detect conflicting ARIA and native HTML attributes |
| aria-attr-valid-values | warning | Validate ARIA attribute values |
| aria-hidden-focusable | error | Detect aria-hidden on focusable elements |
| aria-naming-prohibited | error | Detect aria-label on naming-prohibited elements |
| aria-role-conflicts | warning | Detect conflicts between explicit and implicit role |
| empty-heading | warning | Detect empty heading elements |
| fieldset-has-legend | warning | Require legend in fieldset |
| label-has-control | error | Detect label without associated control |
| landmark-roles | warning | Detect nested landmark roles |
| media-has-captions | warning | Require captions/subtitles track on video |
| neighbor-popovers | off | Detect non-adjacent popover triggers and targets |
| no-abstract-role | error | Detect abstract ARIA roles |
| no-ambiguous-navigable-target-names | warning | Detect invalid target name keywords |
| no-aria-hidden-body | error | Detect aria-hidden on body element |
| no-consecutive-br | warning | Detect consecutive br elements |
| no-duplicate-landmark | warning | Require aria-label on duplicate landmarks |
| no-dup-class | warning | Detect duplicate class names |
| no-positive-tabindex | warning | Detect positive tabindex values |
| no-redundant-role | warning | Detect redundant explicit ARIA roles |
| no-refer-to-non-existent-id | error | Detect references to non-existent ids |
| no-role-on-meta-elements | error | Detect role/aria-* on meta elements |
| require-accessible-name | error | Require accessible name on interactive elements |
| required-h1 | error | Require h1 element |
| table-has-caption | warning | Require caption on data tables |
| table-row-column-alignment | warning | Detect inconsistent table column counts |
| use-list | warning | Suggest list elements for bullet-prefixed text |
| wai-aria | error | Validate WAI-ARIA roles and attributes |
| no-aria-disabled-link | warning | Detect aria-disabled on anchor with href |
| no-generic-role | warning | Detect explicit role="generic" |
| no-aria-checked-mismatch 🔧 | warning | Detect aria-checked on checkbox/radio with checked |
| th-has-scope | warning | Require scope on th elements |
| no-duplicate-accesskey | warning | Detect duplicate accesskey values |
Naming Convention
| Rule | Default | Description |
|------|---------|-------------|
| class-naming | off | Enforce class name conventions |
Maintainability
| Rule | Default | Description |
|------|---------|-------------|
| no-hard-code-id | off | Detect hardcoded id attributes |
| no-inline-style | warning | Detect inline style attributes |
| no-javascript-url | error | Detect javascript: URLs |
| no-obsolete-doctype 🔧 | warning | Detect legacy XHTML/HTML4 doctypes |
| no-use-event-handler-attr | warning | Detect event handler attributes |
| no-form-without-action | warning | Detect form without action attribute |
Style
| Rule | Default | Description |
|------|---------|-------------|
| case-sensitive-attr-name 🔧 | warning | Detect uppercase attribute names |
| case-sensitive-tag-name 🔧 | warning | Detect uppercase tag names |
| character-reference 🔧 | warning | Detect unescaped & characters |
| ineffective-attr | warning | Detect attributes with no effect |
| no-boolean-attr-value 🔧 | warning | Detect values on boolean attributes |
| no-default-value 🔧 | warning | Detect attributes set to their default value |
| no-target-blank-without-rel 🔧 | warning | Require rel="noopener" on target="_blank" |
| prefer-native-over-aria | warning | Prefer native HTML elements over ARIA roles |
Packages
| Package | Description | |---------|-------------| | rintenki | Linter core (Rust + napi-rs) | | rintenki-lsp-server | LSP server | | rintenki-vscode | VS Code extension | | @rintenki/parser-utils | Shared parser interface | | @rintenki/vue-parser | Vue SFC parser | | @rintenki/jsx-parser | JSX/TSX parser | | @rintenki/erb-parser | eRuby parser | | @rintenki/astro-parser | Astro parser |
Supported Platforms
macOS (arm64) / Linux (x64) / Windows (x64)
Inspired by
License
MIT
