CLI tool
antfu/case-police avatar
antfu/case-police

antfu/case-police: automatic capitalization checks for source files

🚨 Make the case correct, PLEASE!

1,424 stars91 forksTypeScriptMIT

At a glance

What is it?
CasePolice is a TypeScript-based CLI and ESLint plugin that corrects the capitalization of names in project files. It suits repositories that want consistent documentation, product names, and technical spellings without manually reviewing every mixed-case token.
Who is it for?
Adopt CasePolice when capitalization consistency is a repository rule that can be expressed through a dictionary and your existing ESLint or CI workflow. Do not choose it for projects that need broad semantic spelling correction or configurable domain language beyond its dictionary model.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

CasePolice targets mixed-case naming errors

CasePolice addresses a narrow but recurring maintenance problem: technical names appear in the wrong capitalization in source comments, Markdown, configuration files, and documentation. The README examples include GitHub, TypeScript, macOS, and VS Code. Its goal is to find known names such as these and rewrite `Github` to `GitHub`, while leaving the text otherwise unchanged. This is useful for repositories where readers, contributors, and external users depend on a consistent public vocabulary. It is aimed at developers who want an automated check in a local command, an ESLint rule, or continuous integration.

The tool is not a general spell checker. It operates from known names stored in a dictionary, and the README states that only words containing both uppercase and lowercase letters are fixed. As a result, `github` and `GITHUB` remain unchanged. That restriction makes accidental edits less likely, but it also means the command cannot normalize every spelling or detect unknown product names. The project does not claim to understand whether a word is a trademark, an identifier, or a sentence-level term.

Dictionary-driven scanning and selective rewriting

The documented data flow begins with file selection. Without file arguments, CasePolice scans text files under the current directory and respects `.gitignore`. It can instead receive specific files or glob patterns, which makes it possible to limit a check to Markdown, HTML, or another set of files. The README also documents comma-separated ignore patterns through `--ignore`.

After selecting files, CasePolice compares their contents with names in its dictionary. The default dictionary is organized under the repository's `packages/case-police/dict` path and can be filtered with `--presets`. A project can merge additional entries with `-d, --dict <path>`, or disable the built-in entries with `--no-default`. Individual rules can be removed with `--disable`.

The important distinction is between checking and fixing. Running without `--fix` reports cases that violate the dictionary and exits with a non-zero status, which the README identifies as suitable for CI. Running with `--fix` rewrites the files. Because the command can modify tracked files, the README explicitly tells users to commit unsaved work before running the fixing mode.

Running the CLI for a first repository check

The project is available through npm, and the README gives `npx case-police --fix` as the first-use command. Before using that command, commit any unsaved work because the fixing mode rewrites source files. The command scans the current project and corrects the case of names known to the dictionary.

A non-mutating check is appropriate when you want to see the result in CI or during review. The README documents the same CLI without `--fix` for this purpose. The command should return a non-zero exit code when it finds a case violation. The README does not specify a separate global installation command, so a first use can begin directly with `npx`.

If the project should be checked only in selected paths, pass files or glob patterns as positional arguments:

bash
npx case-police "**/*.md" path/to/file.html

This example limits the scan to Markdown files and one HTML file. The README documents the CLI options `--ignore`, `--disable`, `--no-default`, `--dict`, and `--presets`, but it does not provide a full configuration example for every option.

ESLint integration for flat and legacy configurations

CasePolice also ships as an ESLint plugin named `eslint-plugin-case-police`. The README documents a flat configuration setup and explicitly states that, since version `2.0.0`, the plugin supports the flat config style. Projects using the legacy config are directed to version `1.x.x`.

Install the plugin as a development dependency:

bash
npm i -D eslint-plugin-case-police

For a flat config, the documented recommended setup is:

js
// .eslint.config.js
import pluginCasePolice from "eslint-plugin-case-police";

export default [
  ...pluginCasePolice.configs.recommended,
];

The README also shows a direct rule configuration. This form targets JavaScript, TypeScript, JSX, and TSX-like files through the documented glob, registers the plugin, and enables `case-police/string-check` as a warning:

js
// .eslint.config.js
import pluginCasePolice from "eslint-plugin-case-police";

export default [
  {
    name: 'case-police',
    files: ['**/*.?([cm])[jt]s?(x)'],
    plugins: {
      'case-police': pluginCasePolice,
    },
    rules: {
      'case-police/string-check': 'warn',
    },
  },
]

The legacy route uses a separate package version and a conventional `.eslintrc` extension. This version boundary matters for upgrades because v2 documentation does not describe legacy configuration support.

Dictionary scope, ignores, and file-level exceptions

CasePolice has two documented escape mechanisms for content that should not be checked normally. Add `@case-police-disable` in a file to disable the case check for that file. For a narrower exception, add `@case-police-ignore` followed by the words to skip. The README says to separate multiple ignored words with commas.

The example uses an exception for `Uri` because a property expression can contain a name that should not be rewritten by the project's dictionary:

ts
// @case-police-ignore Uri

console.log(something.Uri.path)

These comments are repository-level controls, not runtime configuration. They are useful when a codebase has a technical identifier, generated content pattern, or domain term that conflicts with a general naming rule. The README does not describe a separate ignore configuration file or a mechanism for automatically learning new names from the source tree. A project-specific dictionary file remains the documented extension point for additional entries.

Maintenance, licensing, and the boundary against general spelling tools

The repository is not archived. Its last push was on 2026-04-15, and the listed latest release is `v2.2.1` from 2026-04-15. That date does not by itself establish a support policy, compatibility matrix, or long-term maintenance commitment. The repository contains a `package.json`, a `pnpm-lock.yaml`, workspace configuration, and package-level sources, so dependency and release management are visible project concerns rather than undocumented claims.

The repository identifies its license as MIT and links to an MIT `LICENSE` file. That is a permission to use, copy, modify, and distribute the software under the terms of that license, subject to its notice and conditions. This article does not interpret the license for a particular organization or workflow.

The closest documented alternative is `actions-case-police`, described in the README as a related project for using correct letter case in GitHub issues and pull requests. CasePolice is aimed at local source files and ESLint rules. `actions-case-police` is aimed at GitHub content. That difference makes the latter relevant to repository metadata and issue workflows, while CasePolice fits source-tree consistency checks. Neither should be mistaken for a general spelling validator.

Editorial conclusion

Adopt CasePolice when capitalization consistency is a repository rule that can be expressed through a dictionary and your existing ESLint or CI workflow. Do not choose it for projects that need broad semantic spelling correction or configurable domain language beyond its dictionary model. Verify first that your most important names are represented by the built-in dictionary or can be added to a custom dictionary, then run the CLI without --fix in CI.

Frequently asked questions

Does CasePolice modify lowercase and uppercase versions of a known name?

No. The README says that only words containing both uppercase and lowercase letters are fixed, so `Github` can become `GitHub`, while `github` and `GITHUB` remain unchanged.

How can CasePolice be used without rewriting repository files?

Run `case-police` without `--fix`. The README says this exits with a non-zero code when it finds a case violation, which makes the check suitable for CI.

Can CasePolice check only Markdown files?

Yes. The README documents positional files and glob patterns, with `npx case-police "**/*.md" path/to/file.html` as an example of checking Markdown files and one HTML file.

Official sources

  1. antfu/case-police on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/antfu-case-police.svg)](https://hysenlabs.com/projects/antfu-case-police)

Was this useful?