memelint
memelint lints the words that spread through comments, docstrings, and documentation. It tells you which words and sentences do not follow Simplified Technical English (ASD-STE100), with an allowlist for the words of your project.
Each finding gives the file, the position, the severity, the message and the rule:
$ memelint check
foo.py:2:29: error: 'ensure' is not approved; use 'make sure' [STE 1.1]
foo.py:3:7: error: 'don't' is a contraction; write the words in full [STE 4.2]
foo.py:3:13: error: 'delve' is not in the STE dictionary; if it is a technical name, add it to memelint.toml [STE 1.6]
foo.py:4:7: error: sentence has 28 words; the STE limit for descriptive text is 25 [STE 6.3]
foo.py:4:7: error: 'closing' is the -ing form of 'close'; STE allows only the infinitive, imperative, past tense and past participle [STE 3.5]
The exit code is 1 when there is an error.
Installing
ASD-STE100 is copyrighted, thus the binary does not contain its dictionary. The first run downloads the PDF from ASD and makes the vocabulary in ~/.cache/memelint/. The Nix package makes it when it builds.
On your machine
Use the install script, or use Nix.
The install script
The release binaries are for Linux and macOS, on x86_64 and aarch64:
curl -fsSL https://memelint.sh | sh
memelint check
Nix
With Nix, there is no installation. This builds the checker with the vocabulary and with each tree-sitter grammar that nixpkgs has, and runs it:
$(nix-build --no-out-link \
https://github.com/antimemes/memelint/archive/main.tar.gz)\
/bin/memelint check
With flakes:
nix run github:antimemes/memelint -- check
In GitHub Actions
Put this in .github/workflows/memelint.yml. The findings become annotations on the pull request:
name: memelint
on:
push:
branches: [main]
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: antimemes/memelint@latest
Configuration
memelint reads memelint.toml at the project root. Each key is optional. The first line gives your editor the schema:
#:schema https://raw.githubusercontent.com/antimemes/memelint/main/crates/memelint/memelint.schema.json
profile = "strict" # "strict" or "basic"
words = ["gantry", "sprocket"]
word-lists = ["words.txt", "https://example.com/team-words.txt"]
default-word-lists = true
ignore = ["vendor/", "*.generated.go"]
[rules]
"6.3" = "warning" # "error", "warning" or "off"
[languages.rust] # for the files of one language
words = ["monomorphize"]
word-lists = ["rust-words.txt"]
default-word-lists = true
[languages.rust.rules]
"1.6" = "off"
| Key | Effect |
|---|---|
profile | the severity of each rule, see Rules |
rules | the severity of one rule |
words | the technical names and verbs of the project, see Words |
word-lists | files, URLs and bundled lists of words |
default-word-lists | use the bundled lists (default: true) |
ignore | paths that memelint does not examine, in the syntax of .gitignore |
languages.<name> | the same keys for the files of one language, see Languages |
Words
The ASD-STE100 dictionary has approximately 900 words. The technical names and technical verbs of your domain are not in it, and the standard lets you use them. Tell memelint which they are:
words: a list inmemelint.toml.word-lists: files with one word on each line and#comments. An entry is a path from the directory ofmemelint.toml, a URL, or the name of a bundled list.default-word-lists: the bundled lists are on unless this isfalse. Thesoftwarelist applies to all files, and the list of a language to its files.
The entries add to each other. memelint accepts a listed word with its usual inflections: the plural, -ed and -ing.
memelint fetch downloads the URLs into ~/.cache/memelint/words/, and memelint check reads them from there.
The bundled lists are software, c, cpp, go, java, javascript, markdown, nix, python, rust, toml, tsx and typescript. Their text is in the repository. They are not complete. If you add words, send a pull request.
To use only your lists:
default-word-lists = false
word-lists = ["words.txt"]
Rules
ASD-STE100 Issue 9 has 53 rules. A program can check a part of them. memelint checks these:
| Rule | Finding |
|---|---|
| 1.1 | a word that is not approved, with the approved alternatives, for example commence (use start) |
| 1.2 | an approved word in a part of speech in which it is not approved. For example, test is a noun, thus “do a test” and not “test it” |
| 1.6 | a word that is not in the dictionary and not in your word list, for example kubelet. Put the words of your project in memelint.toml, and they are approved |
| 3.5 | the -ing form of an approved verb, for example starting |
| 4.2 | a contraction, for example don't |
| 6.3 | a sentence of more than 25 words |
Each rule has a severity: error, warning or off. The exit code is 1 when there is an error. The profile sets the severity of each rule:
| Profile | Effect |
|---|---|
strict (the default) | each finding is an error |
basic | 1.6 and 6.3 are warnings |
[rules] changes one rule, and [languages.<name>.rules] changes it for the files of one language. The language value applies first, then [rules], then the profile:
profile = "basic"
[rules]
"4.2" = "off"
[languages.markdown.rules]
"1.6" = "off"
A rule that gives no findings cannot be set. memelint stops with an error message when it reads memelint.toml.
Languages
memelint lints each language that has a tree-sitter grammar. The grammar name is the key of [languages.<name>], for example rust, python, cpp or markdown.
Rust, Python, JavaScript, TypeScript, Go, C, Java, Nix, TOML and Markdown are compiled in. For each other language memelint loads <name>.so from a grammar directory, in this sequence:
--grammars <dir>- each directory in
MEMELINT_GRAMMARS ~/.local/share/memelint/grammars
These are the grammar files that Neovim and nixpkgs make. The Nix package sets MEMELINT_GRAMMARS to all the grammars in nixpkgs. When a file has no grammar, memelint does not examine it, and gives a note at the end.
A [languages.<name>] table has the keys words, word-lists, default-word-lists and rules, for the files of that language.
Markdown files are prose. memelint reads their paragraphs, headings and table cells, and not their code blocks.