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

markdownlint-rule-spellcheck

v0.2.0

Published

A markdownlint custom rule for spelling checks powered by CSpell.

Readme

markdownlint-rule-spellcheck

Test Lint Coverage Node.js: >=22.18 License: MIT

A markdownlint custom rule for prose spelling, powered by CSpell.

Contents

Installation

Requires Node.js 22.18 or later and markdownlint 0.42.0 or later.

npm install --save-dev markdownlint-cli2 markdownlint-rule-spellcheck

Usage

In .markdownlint-cli2.jsonc:

{
  "customRules": ["markdownlint-rule-spellcheck"]
}

Then:

npx markdownlint-cli2 "**/*.md"

For example, save this as example.md:

# Say helo to the world

Running npx markdownlint-cli2 example.md produces:

markdownlint-cli2 v0.24.0 (markdownlint v0.42.0)
Finding: example.md
Linting: 1 file
Summary: 1 issue in 1 file
example.md:1:7 error spellcheck Prose words should be spelled correctly [Misspelled word: "helo". Suggestions: hello, helio, halo.]

Spelling checks are enabled by default. Suppress them with <!-- markdownlint-disable spellcheck --> or disable spellcheck in markdownlint configuration.

To accept project-specific words, collect candidates, review .spellcheck.txt and remove typos, then add it to your configuration:

npx markdownlint-rule-spellcheck collect "**/*.md" --output .spellcheck.txt
# Edit .spellcheck.txt: keep only words you want to accept.
npx markdownlint-rule-spellcheck add ./.spellcheck.txt
npx markdownlint-cli2 "**/*.md"

add updates .markdownlint.json without replacing existing settings or duplicating dictionaries. Use --config path/to/config.json for another JSON configuration; JSONC and YAML are not supported by add.

Configuration

In .markdownlint.json:

{
  "spellcheck": {
    "dictionaries": {
      "en": ["@cspell/dict-en_us", "./.spellcheck.txt"]
    },
    "autocorrect": false,
    "markdown": {
      "frontMatter": true
    }
  }
}

All options are optional. Local .txt dictionary paths are relative to the working directory. Each file contains one case-sensitive word per line; blank lines and # comments are ignored. Missing files are errors.

American English is included for offline use. To replace it, install a CSpell dictionary package:

npm install --save-dev @cspell/dict-es-es

Then configure .markdownlint.json:

{
  "spellcheck": {
    "dictionaries": {
      "es": ["@cspell/dict-es-es", "./.spellcheck.es.txt"]
    }
  }
}

Omitting dictionaries uses American English. An explicit language map replaces it; include an en entry if you still want English. Each language needs a nonempty list of packages or .txt files. A word is accepted by any configured dictionary, and suggestions come from all languages. Language keys label the dictionaries; they do not automatically install or select a language.

For English and Spanish together:

{
  "spellcheck": {
    "dictionaries": {
      "en": ["@cspell/dict-en_us", "./.spellcheck.txt"],
      "es": ["@cspell/dict-es-es", "./.spellcheck.es.txt"]
    }
  }
}

Create the vocabulary files before referencing them, or omit them. To add technical vocabulary, install @cspell/dict-software-terms and append it to the relevant language's list.

Install dictionary packages in your project; English is included with the rule. Only package dictionaries and local .txt files are supported, not CSpell configuration imports, Hunspell files, or system dictionaries.

Creating a project dictionary

Run collect:

npx markdownlint-rule-spellcheck collect "**/*.md" --output .spellcheck.txt

Candidates are sorted and deduplicated, using your configured dictionaries, front matter field selections, file exclusions, and suppression comments.

The output path defaults to .spellcheck.txt if omitted. Existing files are never overwritten. Review the file and remove typos before adding it to your dictionaries. Normal linting never changes dictionary files.

Use add --language to put vocabulary under a specific language (default: en):

npx markdownlint-rule-spellcheck add ./.spellcheck.es.txt --language es

add preserves other languages and adds the file to the selected language, creating that entry if needed. It does not select a language dictionary for you.

YAML front matter

YAML front matter checking is enabled by default for string values, including nested objects and arrays. Keys, numbers, booleans, and comments are skipped. Anchored strings are checked once, not at each alias. Malformed YAML is an error.

Select fields in .markdownlint.json:

{
  "spellcheck": {
    "markdown": {
      "frontMatter": {
        "include": ["title", "description", "authors.name", "metadata"],
        "exclude": ["metadata.id", "metadata.url"]
      }
    }
  }
}

Omitting include checks all string values; include: [] checks none. Dotted paths select nested fields, including fields inside arrays without numeric indices. Selecting a parent includes its subtree; exclusions win. Paths are case-sensitive, not globs.

To skip front matter, set "spellcheck": { "markdown": { "frontMatter": false } } in .markdownlint.json.

Quoted strings and block values are checked but never autocorrected. Plain values can be corrected only when the result remains a YAML string.

Corrections

By default, diagnostics include suggestions but no fixes. Set autocorrect: true and run npx markdownlint-cli2 --fix "**/*.md" to enable replacements.

For example, helo becomes hello. Fixes use the first suggestion only when it differs by one letter edit or transposition. Lowercase and title case are preserved; ALL CAPS, mixed case, and words inside dotted, hyphenated, numbered, or identifier-like tokens are left unchanged. Review the diff: a correction can still change your meaning.

Scope

Checks spelling, not grammar, in headings, paragraphs, lists, quotes, tables, link labels, and image descriptions.

Skips code, HTML blocks and tags, link destinations/titles/reference definitions, URLs, email addresses, and entity-encoded word fragments. Does not split identifiers; add project terms through .txt dictionaries or install technical dictionaries.

Accented words and apostrophes are supported. Tokens containing numbers or connector punctuation (including underscores) are skipped: sha256, can't2stop, and wrong_token. Hyphens separate words, so helo-world flags helo but is not autocorrected. Markdown emphasis such as _helo_ is checked.

Liquid expressions ({{ ... }}) and tags ({% ... %}), including multiline forms, are skipped; surrounding prose is checked. Each ends at the first matching closing delimiter. Unmatched openers remain ordinary text.