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

dtlint-core

v0.2.0

Published

Design token linter: flags hardcoded hex/px/font values and suggests the nearest design token

Readme

dtlint — Design Token Linter

CI License: MIT

Scans React / Vue / CSS / Tailwind codebases for hardcoded hex colors, px measurements, and generic font stacks — and suggests the nearest official design token using perceptual CIEDE2000 (Delta-E) color matching, not exact string comparison.

src/styles.css
  3:10   error  #1a73e8 (color) → use color-brand-blue [ΔE 0] (auto-fixable)
  6:28   error  #3b82f6 (border-bottom) → use color-brand-blue [ΔE 5.66]
  12:11  warn   17px (margin) → use space-4 [Δ 1px]
  16:16  error  Arial, sans-serif (font-family) → use font-body
  23:15  error  #00ff9c (background) → no token within threshold — needs a design decision

Why Delta-E? #1b74e9 is one RGB step away from your brand blue #1a73e8 — no human can tell them apart (ΔE 0.38), so dtlint auto-fixes it. #3b82f6 looks similar but is perceptibly different (ΔE 5.66), so dtlint suggests the token and leaves the decision to you. String-matching linters can't make that distinction.

Packages

| Package | Registry | What it is | |---|---|---| | dtlint | npm | CLI: scan, check (CI gate), fix, baseline | | @dtlint/core | npm | Engine: token ingestion, Delta-E matching, scanners, fix engine, SARIF | | @dtlint/language-server | npm | LSP server — VS Code, Neovim, JetBrains, any LSP client | | dtlint-vscode | VS Code Marketplace | Extension: live diagnostics, quick fixes, fix-all, token hot reload |

Quick start

npm install -D dtlint          # once published; from source: npm install && npm run build
  1. Export your design tokens from Figma (via Tokens Studio or figmage) as DTCG or Style Dictionary JSON.
  2. Create .dtlintrc.json at your repo root:
{
  "tokens": ["./design-tokens/tokens.json"],
  "rules": {
    "hardcoded-color":   { "severity": "error", "autofixDeltaE": 2, "suggestDeltaE": 10 },
    "hardcoded-spacing": { "severity": "warn",  "autofixDeltaPx": 0, "suggestDeltaPx": 4 },
    "generic-font":      { "severity": "error" }
  },
  "ignore": ["**/*.stories.tsx", "**/generated/**"]
}
  1. Run it:
npx dtlint scan src              # report findings with suggestions
npx dtlint fix src --dry-run     # preview auto-fixes, then run without --dry-run
npx dtlint check src             # CI mode: exit 1 on violations

Try it on the bundled fixture: npm run lint:self.

Configuration reference

| Key | Default | Meaning | |---|---|---| | tokens | — (required) | Paths to token JSON files, relative to the config file. DTCG ($value/$type, {alias} references) and legacy Style Dictionary (value/type) both supported. | | rules.hardcoded-color.severity | error | off / warn / error | | rules.hardcoded-color.autofixDeltaE | 2 | Matches at or below this ΔE are safe to auto-fix (imperceptible difference) | | rules.hardcoded-color.suggestDeltaE | 10 | Matches beyond autofix but within this bound are suggested for review; farther values are flagged with no candidate | | rules.hardcoded-spacing.autofixDeltaPx / suggestDeltaPx | 0 / 4 | Same two-threshold model for the spacing scale | | rules.hardcoded-spacing.properties | margin/padding/gap/inset/border-radius/… | CSS properties whose px values are checked | | rules.generic-font.severity | error | Font stacks whose primary family isn't token-approved | | ignore | node_modules, dist, build | Glob patterns to skip (extends, not replaces, defaults) | | replacement.css / replacement.js | var(--{name}) | Replacement template; {name} = kebab-case token path |

What gets scanned

  • CSS / SCSS / LESS — hex, rgb()/hsl() literals; px on spacing properties; font-family
  • JS / TS / JSX / TSXstyle={{ }} objects (string and React numeric px values), color-valued attributes (fill="#d93025"), styled.* / css tagged template literals, Tailwind arbitrary values (bg-[#1A73E8], p-[17px]) in className
  • Vue SFCs<style> blocks, <script> blocks, <template> inline style="" attributes and Tailwind arbitrary values in class=""

Tailwind arbitrary values are suggested but never auto-rewritten — the correct theme class name can't be derived from the token file alone.

Commands

dtlint scan  [paths...]   report findings (--format human|json|sarif, --output <file>)
dtlint check [paths...]   CI gate: exit 1 on error-severity findings (--max-warnings <n>)
dtlint fix   [paths...]   apply auto-fixes above the confidence threshold (--dry-run)
dtlint baseline [paths...] snapshot existing violations as accepted debt

Incremental adoption (baseline)

Legacy codebases have hundreds of pre-existing violations. Snapshot them once:

npx dtlint baseline src        # writes .dtlint-baseline.json beside your config
git add .dtlint-baseline.json

From then on scan/check report only new violations — CI stays green on old debt and blocks regressions. Fingerprints are line-number-independent, so moving code doesn't resurface baselined findings. Use --no-baseline to see everything; delete the file to reset.

CI: blocking PRs

See examples/github-action/dtlint.yml for both options:

  • Composite actionuses: nandkk05/dtlint@v1 with paths / max-warnings inputs.
  • SARIF uploaddtlint scan --format sarif + github/codeql-action/upload-sarif renders findings as inline annotations on the PR diff and in the Security tab.

Editor integration

VS Code — install the dtlint extension (or grab the .vsix from Releases). It runs the language server automatically: live diagnostics, quick fixes (Replace #1A73E8 with color-brand-blue), a dtlint: Fix all command, source.fixAll on-save support, and hot reload when your token file changes.

Any other LSP editor (Neovim, JetBrains, Helix, …) — the server is a standalone npm package speaking stdio:

npm install -g @dtlint/language-server
dtlint-language-server --stdio

Example Neovim (lspconfig-style) setup:

vim.lsp.config('dtlint', {
  cmd = { 'dtlint-language-server', '--stdio' },
  filetypes = { 'css', 'scss', 'less', 'javascriptreact', 'typescriptreact', 'vue' },
  root_markers = { '.dtlintrc.json', '.dtlintrc', 'dtlint.config.json' },
})

Architecture

packages/
  core/             token ingestion → Delta-E matcher → scanners → fix engine → SARIF/baseline
  cli/              dtlint scan/check/fix/baseline (thin wrapper over core)
  language-server/  LSP server over core (diagnostics, code actions, fix-all)
  vscode/           LSP client + esbuild bundle for the Marketplace

Both the CLI and every editor share the same engine and the same .dtlintrc.json, so the IDE and CI can never disagree about what's a violation.

Contributing & releasing

License

MIT