forked from rook/rook
mkdocs uses a markdown renderer that is hardcoded to 4 spaces per tab
for detecting indentation levels, including ordered- and
unordered-lists. Since we cannot easily change the renderer, begin using
a markdown linter in CI that will fail if official docs do not adhere to
the spacing rules.
As a starting point, the markdownlint config does not begin with the
default set of checks, which might overwhelm attempts to fix them.
Instead, focus on list-tab-spacing rules and a few other highly useful
checks.
markdownlint also has some gaps in its abilities that allow common Rook
doc issues to pass acceptance. However, it allows creating custom
linting plugins. Create 2 such linting plugins to check 2 things:
- all doc lines (except code blocks) must be aligned to a 4-space
boundary, without exception. This ensures that markdown will render
correctly with mkdocs. This unfortunately makes it possible to create
lists that are internally aligned strangely.
- admonitions must all follow the same format of
```
!!! header
body
```
For the strange lists, this is allowed and renders correctly, but it
looks strange:
```md
- first bullet
- second bullet
still second bullet
- third bullet
has a paragraph
of text inside
- last bullet
Signed-off-by: Blaine Gardner <blaine.gardner@ibm.com>
53 lines
2.0 KiB
JavaScript
53 lines
2.0 KiB
JavaScript
const admonition_identifier = "!!!"
|
|
const body_tab_space_indent = 4
|
|
|
|
module.exports = {
|
|
"names": [ "mkdocs-admonitions" ],
|
|
"description": "Enforce mkdocs admonitions are formatted properly",
|
|
"tags": [ "test" ],
|
|
"parser": "none",
|
|
"function": function rule(params, onError) {
|
|
const { lines } = params;
|
|
const countTabSpaces = (line) => {
|
|
start_spaces = /^\s*/;
|
|
return line.match(start_spaces)[0].length
|
|
};
|
|
lines.forEach((line, i) => {
|
|
const thisLineNumber = i+1 // "lineNumber" field is ones-based
|
|
const bodyLineIndex = i+1 // body line should start after header
|
|
const bodyLineNumber = bodyLineIndex + 1
|
|
|
|
const isAdmonitionHeader = ( line.trimLeft().startsWith(admonition_identifier) )
|
|
if ( !isAdmonitionHeader ) return;
|
|
|
|
const admonition_start = line.indexOf(admonition_identifier)
|
|
const expected_body_tab_spaces = ''.padStart(admonition_start+body_tab_space_indent, ' ')
|
|
if ( lines[i+1].trim().length == 0 ) {
|
|
// body should immediately follow header
|
|
onError({
|
|
"lineNumber": thisLineNumber + 1,
|
|
"detail": "found blank line after admonition header -- body text should immediately follow header",
|
|
"context": line,
|
|
"fixInfo": {
|
|
"lineNumber": thisLineNumber + 1,
|
|
"deleteCount": -1, // delete the line
|
|
},
|
|
});
|
|
} else if ( lines[bodyLineIndex] != expected_body_tab_spaces + lines[bodyLineIndex].trimStart() ) {
|
|
// body should be indented exactly 4 spaces from start of header
|
|
got_tab_spaces = countTabSpaces(lines[bodyLineIndex])
|
|
onError({
|
|
"lineNumber": bodyLineNumber,
|
|
"detail": "admonition/callout body is not indented properly",
|
|
"context": lines[bodyLineIndex],
|
|
"fixInfo": {
|
|
"lineNumber": bodyLineNumber,
|
|
"deleteCount": got_tab_spaces,
|
|
"insertText": expected_body_tab_spaces, // insert at beginning of lineNumber
|
|
},
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|