Keep the terms and the docs in step
A term set says which names are preferred, which are admitted and which are
deprecated. This page turns that into prose checks. manni term write -f vale
renders the set as a Vale style named Terms. Vale then flags a deprecated
name, a term in the wrong case, or an acronym used before its expansion. manni term lint runs the same Vale configuration over the
definitions themselves.
Every transcript below is real output from the built tool and Vale 3.20.0.
Before you start
Section titled “Before you start”- A term set that
manni term checkpasses. Get started builds one. - Vale on PATH. Both verbs start
valeas a process.write -f vale -o <dir>runs without it, and so doeslintwhen no entry has a definition, abstract or scope note. - A Vale configuration with a
StylesPath. The example uses a house style namedHouse, with a sentence-length rule and a rule against filler words.
The example set has three terms. progressive lens has the alt-labels PAL
and graduated lens, and the hidden-label no-line bifocal. Kubernetes
has the alt-label K8s and the hidden-label Kubernates. corrective lens
has neither.
Generate the style
Section titled “Generate the style”-
Tell manni where Vale’s configuration is.
tools:is a top-level key of the family config, besidecollections:. Every domain that runs Vale reads it:manni.config.yaml collections:- name: sitepaths:- "docs/**/*.md"tools:vale:config: .vale.ini.vale.ini StylesPath = .vale/stylesMinAlertLevel = suggestion[*.md]BasedOnStyles = HouseWithout
tools.vale.config, Vale looks for its configuration itself, as it does when you run it. -
Write the style. With no
-o, manni asks Vale where its styles directory is, and writesTerms/there:Terminal window manni term write -f valeWrote 3 terms to .vale/styles/TermsCasing.yml 2 labelsLowercase.yml 3 labelsDeprecated.yml 2 swapsPAL.yml 1 acronymnotice: no section of .vale.ini uses the Terms style. Add it to BasedOnStyles:[*.md]BasedOnStyles = House, Termsmanni never edits a Vale configuration. The notice names the line to add, and the file to add it to.
-
Wire the style in. Add
Termsto the section the notice names:.vale.ini StylesPath = .vale/stylesMinAlertLevel = suggestion[*.md]BasedOnStyles = House, TermsRun
manni term write -f valeagain and the notice is gone. -
Run Vale over a guide. This one breaks each kind of rule once:
docs/guides/fitting.md ---title: Fitting lensesconcepts: [progressive lens, corrective lens, Kubernetes]---# Fitting lensesMost customers over fifty ask for a PAL.A progressive lens (PAL) has no visible line, unlike a no-line bifocal.Our fitting service runs on kubernetes.The booking system also runs on Kubernates.Terminal window $ vale docs/guides/fitting.mddocs\guides\fitting.md8:37 warning Spell out 'PAL' on first use, as 'progressive lens (PAL)'. Terms.PAL10:56 warning Use 'progressive lens' instead of 'no-line bifocal'. Terms.Deprecated12:29 error Use 'Kubernetes' instead of 'kubernetes'. Terms.Casing14:33 warning Use 'Kubernetes' instead of 'Kubernates'. Terms.Deprecated✖ 1 error, 3 warnings and 0 suggestions in 1 file.PALon line 10 is not flagged, because its expansion sits beside it.
The generated style
Section titled “The generated style”Each file is built from one kind of label, and each opens with a marker line:
| File | Vale check | Built from | Level |
|---|---|---|---|
Terms/Casing.yml | substitution | labels and alt-labels that hold a capital and don’t start with a lowercase letter, such as Kubernetes, K8s or C++ | error |
Terms/Lowercase.yml | substitution | labels and alt-labels entirely in lowercase | error |
Terms/SentenceStart.yml | substitution | labels and alt-labels that start lowercase and hold a capital later, such as iPhone | error |
Terms/Deprecated.yml | substitution | hidden-labels, each swapped for its entry’s label | warning |
Terms/<ACRONYM>.yml | conditional | each all-caps alt-label of a label that is not all caps, unless the alt-label is another term’s label | warning |
A file with nothing to hold is not written. A label that is all caps, such as
API, gets no casing rule and no acronym rule, because it is the name itself.
# Generated by manni term write. Edit the terms, not this file.extends: substitutionmessage: "Write '%[2]s' in lowercase, except to start a sentence."level: errorignorecase: truenonword: truevocab: falseswap: \bcorrective lens\b: "[Cc]orrective lens" \bprogressive lens\b: "[Pp]rogressive lens" \bgraduated lens\b: "[Gg]raduated lens"A term that starts lowercase may still start a sentence. Lowercase.yml and
SentenceStart.yml allow a capital first letter, and both messages print what
the writer wrote rather than the pattern. manni’s own glossary writes this one
for meta-schema URI:
# Generated by manni term write. Edit the terms, not this file.extends: substitutionmessage: "Write '%[2]s' as the term list spells it, with a capital only to start a sentence."level: errorignorecase: truenonword: truevocab: falseswap: \bmeta-schema uri\b: "[Mm]eta-schema URI"# Generated by manni term write. Edit the terms, not this file.extends: conditionalmessage: "Spell out 'PAL' on first use, as 'progressive lens (PAL)'."level: warningignorecase: falsefirst: '\b(PAL)\b'second: '(?i)progressive lens \((PAL)\)'Three rules keep the style safe to commit:
- manni owns
Terms/. A file there without the marker line is someone else’s, and the write stops with exit2rather than replace it. A marked file the set no longer produces, such as the rule for a removed acronym, is deleted. vale syncleaves the files alone. Commit them beside the config, and let--checksay when they fall behind.- manni writes no vocabulary file. The casing rules above do that job, so
accept.txtstays yours.
To write the style somewhere Vale does not report, pass -o <styles directory>. That form does not start Vale at all.
Lint the definitions
Section titled “Lint the definitions”A definition is prose, and the house voice applies to it too. manni term lint writes each entry’s definition, abstract and scope-note to a
temporary file named <id>.<field>.md. Then it runs Vale once over all of
them, with the same configuration:
manni term lintdocs/terms/kubernetes.md:7 warning manni:term/prose/House.Simply Drop 'Simply'.docs/terms/kubernetes.md:11 warning manni:term/prose/House.Simply Drop 'just'.docs/terms/progressive-lens.md:9 error manni:term/prose/House.Length Keep a sentence under 20 words.
1 error, 2 warnings in 3 termsEach finding sits on the source line of its field. Line 7 is the abstract.
Line 11 is the second line of a literal scope-note: | block, so the finding
lands on that exact line. The definition of progressive lens is a folded
>- block, so its finding sits on the field’s first line.
A voice for definitions alone
Section titled “A voice for definitions alone”A definition is often one long noun phrase, and a sentence-length rule written
for guides fires on it. Vale matches a section by file name, so a
[*.definition.md] section applies to definitions and nothing else:
StylesPath = .vale/stylesMinAlertLevel = suggestion
[*.md]BasedOnStyles = House, Terms
[*.definition.md]House.Length = NOdocs/terms/kubernetes.md:7 warning manni:term/prose/House.Simply Drop 'Simply'.docs/terms/kubernetes.md:11 warning manni:term/prose/House.Simply Drop 'just'.
2 warnings in 3 termsThe length finding is gone, and the exit code is 0. The abstract and
scope-note files still get House.Length, because their names end
.abstract.md and .scope-note.md.
Keep the style current
Section titled “Keep the style current”The style is rendered from the set, so it falls behind whenever a term
changes. --check renders without writing, and exits 1 when a file
differs. Add the hidden-label Kubernets to Kubernetes, and:
$ manni term write -f vale --check.vale/styles/Terms/Deprecated.yml would change$ echo $?1Write the style again, and the check passes:
$ manni term write -f vale --check.vale/styles/Terms is up to date$ echo $?0--dry-run prints the same lines, writes nothing, and exits 0. A file the
set would drop is named too, as in
.vale/styles/Terms/PAL.yml would be removed.