Skip to content

Linter

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

Configuration

By default, the linter ensures that attributes satisfy their definition. In addition, the linter also support a list of optional rules declared as functions in nt.libsonnet to use in config.jsonnet. For example:

local nt = import 'nt.libsonnet';
{
attributes: nt.DefaultAttributes,
noteTypes: nt.DefaultNoteTypes,
linter: {
rules: [
// Declare rules below
nt.LintRules.NoEmptyTitle(),
nt.LintRules.NoDuplicateNoteTitle(),
nt.LintRules.NoDuplicateSlug(),
nt.LintRules.NoDanglingMedia(),
nt.LintRules.NoDeadWikilink(),
],
},
}

Rules have no severity to make sure that violations are fixed instead of accumulating them.

Rules

RuleDescriptionArguments
no-empty-titleEnforce all notes have a non-empty title-
no-duplicate-note-titleEnforce no duplicate between note titles inside the same file-
no-duplicate-slugEnforce no duplicate slugs between notes across files-
no-implicit-slug-on-flashcardEnforce explicit slugs on flashcards to preverse study history on rewriting-
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
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-tag-ifAt least one tag on notes matching the query must match
  • string A query to match notes
  • string[] A list of tags

no-empty-title

Configuration:

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.NoEmptyTitle(),
],
}
}

Example (with violations highlighted):

# Example
## Note:
This is a note.

no-duplicate-note-title

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.NoDuplicateNoteTitle(),
],
}
}

Example (with violations highlighted):

# Example
## Note: The same title is allowed on different types
This is a note.
### Flashcard: The same title is allowed on different types
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

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.NoDuplicateSlug(),
],
}
}

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

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.MinLinesBetweenNotes(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:

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.MaxLinesBetweenNotes(1),
],
}
}

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.

no-dangling-media

Configuration:

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.NoDanglingMedia(),
],
}
}

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:

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.NoDeadWikilink(),
],
}
}

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:

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.NoExtensionWikilink(),
],
}
}

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:

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.NoAmbiguousWikilink(),
],
}
}

Example (with violations highlighted):

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

require-tag-if

Configuration:

config.jsonnet
local nt = import 'nt.libsonnet';
{
linter: {
rules: [
nt.LintRules.RequireTagIf("type:Quote", [
"learning",
"mastering",
])
],
}
}

Example (with violations highlighted):

# Example
## Quote: No Tag
`@name: Anonymous`
This is the first quote.
## Quote: Tag
`@name: Anonymous`
`#useless`
This is the second quote.