npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rintenki

v0.14.5

Published

A fast HTML linter powered by html5ever + napi-rs

Readme

rintenki

A fast HTML linter powered by html5ever + napi-rs.

Documentation

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.json editor completion

Install

npm install rintenki

Usage

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 help

API

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

markuplint

License

MIT