Skip to content

Linter

The linter enforces rules on your notes to ensure their syntax is consistent and makes easy to find them later. It’s particularly interesting as your collection of notes grows over time.

Configuration

The linter reads its configuration from the YAML file .nt/lint. No file exists by default. Ex:

rules:
- name: min-lines-between-notes
args: [2]
- name: no-free-note
includes:
- references/
- name: no-dangling-media
- name: no-dead-wikilink

Rules are declared under the attribute rules. Some rules accept arguments using the attribute args (array of primitive values) and all rules can be restricted to apply on a subset of your notes using the attribute includes (array of glob path expressions).

Rules

RuleDescriptionArguments
no-duplicate-note-titleEnforce no duplicate between note titles inside the same file-
no-duplicate-slugEnforce no duplicate slugs between notes across files-
min-lines-between-notesEnforce a minimum number of lines between notes
  • int The number of lines
max-lines-between-notesEnforce a maximum number of lines between notes
  • int The number of lines
note-title-matchEnforce a consistent naming for notes
  • string A Golang regex
no-free-noteForbid untyped notes-
no-dangling-mediaPath to media files must exist-
no-dead-wikilinkLinks between notes must exist-
no-extension-wikilinkNo extension in wikilinks-
no-ambiguous-wikilinkNo ambiguity in wikilinks-
require-quote-tagAt least one tag on quotes (must match the optional pattern)
  • string A regex that must match all accepted tags on quotes
check-attributeAttributes must satisfy their schema if defined (see below)-

no-duplicate-note-title

Configuration:

.nt/lint
rules:
- name: no-duplicate-note-title

Example (with violations highlighted):

# Example
## Note: The same title is allowed on different kinds
This is a note.
### Flashcard: The same title is allowed on different kinds
This is a flashcard.
## Note: Long title must be unique inside a file
This is a note.
## Note: Long title must be unique inside a file
This is a note with the same title.

no-duplicate-slug

Configuration:

.nt/lint
rules:
- name: no-duplicate-slug

Example (with violations highlighted):

# Example
## Note: The slug attribute is supported
`@slug: note1`
This is a note.
### Note: The same slug cannot be reused
`@slug: note1`
This is a note.
## Note: Slugs must be compatible with URLs
`@slug: not a valid slug`
This is a note.

min-lines-between-notes

Configuration:

.nt/lint
rules:
- name: min-lines-between-notes
args:
- 2

Example (with violations highlighted):

# Example
## Note: One
This is the first note.
## Note: Two
This is the second note.
## Note: Three
This is the third note.
## Note: Four
This is the fourth note.

max-lines-between-notes

Configuration:

.nt/lint
rules:
- name: max-lines-between-notes

Example (with violations highlighted):

# Example
## Note: One
This is the first note.
## Note: Two
This is the second note.
## Note: Three
This is the third note.
## Note: Four
This is the fourth note.

note-title-match

Configuration:

.nt/lint
rules:
- name: note-title-match
args:
- "^(Note|Reference):\s\S.*$"

Example (with violations highlighted):

# Example
## Reference: Example
A title matching the regular expression `(Reference|...):\s\S.*`.
## reference: Example
The kind is in lowercase (allowed but enforced by the linter).

no-free-note

Configuration:

.nt/lint
rules:
- name: no-free-note

Example (with violations highlighted):

# Example
## A free note
This is a free note.
## Note: A typed note
This is a typed note.
## Cheatsheet: Another typed note
This is another typed note.

no-dangling-media

Configuration:

.nt/lint
rules:
- name: no-dangling-media

Example (with violations highlighted):

# Example
![Missing directory](pic.jpeg)
![OK](no-dangling-media/pic.jpeg)
![Wrong extension](no-dangling-media/pic.jpg)
![OK](no-dangling-media/../no-dangling-media/pic.jpeg)
![OK](./no-dangling-media/pic.jpeg)

Configuration:

.nt/lint
rules:
- name: no-dead-wikilink

Example (with violations highlighted):

no-dead-wikilink.md
# Example
## Note: A
[[#B]]
[[#Note: B]]
[[unknown.md]]
## Note: B
[[no-dead-wikilink.md#Note: A]]
[[no-dead-wikilink#Note: A]]

Configuration:

.nt/lint
rules:
- name: no-extension-wikilink

Example (with violations highlighted):

no-extension-wikilink.md
# Example
## Note: Link 1
[[no-extension-wikilink#Note: Link 2]]
## Note: Link 2
[[no-extension-wikilink.md#Note: Link 1]]
## Note: Link 3
[[no-extension-wikilink]]
## Note: Link 4
[[no-extension-wikilink.md]]

Configuration:

.nt/lint
rules:
- name: no-ambiguous-wikilink

Example (with violations highlighted):

# Example
[[books.md]]
[[notes/books.md]]
[[reviews/books.md]]

require-quote-tag

Configuration:

.nt/lint
rules:
- name: require-quote-tag
args:
- "^(life|favorite)$"

Example (with violations highlighted):

# Example
## Note: A Note
Only quotes are concerned by this rule.
## Quote: No Tag
`@name: Anonymous`
This is the first quote.
## Quote: Tag
`@name: Anonymous`
`#useless`
This is the second quote.

check-attribute

Configuration:

.nt/lint
rules:
- name: check-attribute
schemas:
- name: Quotes
kind: quote
path: references
attributes:
- name: name
aliases: [author, illustrator]
type: string
required: true

Example (with violations highlighted):

# Example
## Note: Marcus Aurelius On Others
> What’s bad for the hive is bad for the bee.
## Quote: Summum Bonum
Just that you do the right thing.
## Quote: Memento Mori
`@author: Marcus Aurelius`
You could leave life right now. Let that determine what you do and say and think.

Schemas

Schemas are used to defined attributes and must follow this structure:

.nt/lint
schemas:
- name: Quotes # A name used when reporting violations
kind: quote # Restriction on the note kinds
path: references # Restriction on the note path (glob pattern)
attributes: # Define a list of attributes
- name: name # The attribute name
aliases: [author] # Optional aliases for the attribute name
type: string # One of: array, string (default), boolean, number, object
required: true # Mandatory? (default: false)
inherit: true # Attribute is inheritable by sub-notes? (default: true)

Default schemas (important for the inner working of the application) are predefined:

schemas:
- name: Hooks
attributes:
- name: hook
type: array
inherit: false
- name: Tags
attributes:
- name: tags
type: array
- name: Relations
attributes:
- name: source
inherit: false
- name: references
type: array
- name: inspirations
type: array

Declaring attributes as array is convenient as value will automatically be appended to existing values:

---
tags: life # Same as tags: [life]
---
# A Note
`@tags: life-changing` `#favorite`
This note will have the tags `#life`, `#life-changing`, and `#favorite`.