mirror of
https://github.com/remarkjs/remark-lint.git
synced 2024-09-17 14:47:09 +03:00
137 lines
3.1 KiB
JavaScript
137 lines
3.1 KiB
JavaScript
/**
|
||
* remark-lint rule to warn when headings are indented.
|
||
*
|
||
* ## What is this?
|
||
*
|
||
* This package checks the indent of headings.
|
||
*
|
||
* ## When should I use this?
|
||
*
|
||
* You can use this package to check that headings are consistent.
|
||
*
|
||
* ## API
|
||
*
|
||
* ### `unified().use(remarkLintNoHeadingIndent)`
|
||
*
|
||
* Warn when headings are indented.
|
||
*
|
||
* ###### Parameters
|
||
*
|
||
* There are no options.
|
||
*
|
||
* ###### Returns
|
||
*
|
||
* Transform ([`Transformer` from `unified`][github-unified-transformer]).
|
||
*
|
||
* ## Recommendation
|
||
*
|
||
* There is no specific handling of indented headings (or anything else) in
|
||
* markdown.
|
||
* While it is possible to use an indent to headings on their text:
|
||
*
|
||
* ```markdown
|
||
* # One
|
||
* ## Two
|
||
* ### Three
|
||
* #### Four
|
||
* ```
|
||
*
|
||
* …such style is uncommon, a bit hard to maintain, and it’s impossible to add a
|
||
* heading with a rank of 5 as it would form indented code instead.
|
||
* Hence, it’s recommended to not indent headings and to turn this rule on.
|
||
*
|
||
* ## Fix
|
||
*
|
||
* [`remark-stringify`][github-remark-stringify] formats headings without indent.
|
||
*
|
||
* [api-remark-lint-no-heading-indent]: #unifieduseremarklintnoheadingindent
|
||
* [github-remark-stringify]: https://github.com/remarkjs/remark/tree/main/packages/remark-stringify
|
||
* [github-unified-transformer]: https://github.com/unifiedjs/unified#transformer
|
||
*
|
||
* @module no-heading-indent
|
||
* @author Titus Wormer
|
||
* @copyright 2015 Titus Wormer
|
||
* @license MIT
|
||
* @example
|
||
* {"name": "ok.md"}
|
||
*
|
||
* #␠Hello world
|
||
*
|
||
* Foo
|
||
* -----
|
||
*
|
||
* #␠Hello world␠#
|
||
*
|
||
* Bar
|
||
* =====
|
||
*
|
||
* @example
|
||
* {"name": "not-ok.md", "label": "input"}
|
||
*
|
||
* ␠␠␠# Hello world
|
||
*
|
||
* ␠Foo
|
||
* -----
|
||
*
|
||
* ␠# Hello world #
|
||
*
|
||
* ␠␠␠Bar
|
||
* =====
|
||
*
|
||
* @example
|
||
* {"name": "not-ok.md", "label": "output"}
|
||
*
|
||
* 1:4: Remove 3 spaces before this heading
|
||
* 3:2: Remove 1 space before this heading
|
||
* 6:2: Remove 1 space before this heading
|
||
* 8:4: Remove 3 spaces before this heading
|
||
*/
|
||
|
||
/**
|
||
* @typedef {import('mdast').Root} Root
|
||
*/
|
||
|
||
import plural from 'pluralize'
|
||
import {lintRule} from 'unified-lint-rule'
|
||
import {pointStart} from 'unist-util-position'
|
||
import {visit} from 'unist-util-visit'
|
||
|
||
const remarkLintNoHeadingIndent = lintRule(
|
||
{
|
||
origin: 'remark-lint:no-heading-indent',
|
||
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-indent#readme'
|
||
},
|
||
/**
|
||
* @param {Root} tree
|
||
* Tree.
|
||
* @returns {undefined}
|
||
* Nothing.
|
||
*/
|
||
function (tree, file) {
|
||
visit(tree, 'heading', function (node, _, parent) {
|
||
const start = pointStart(node)
|
||
|
||
// Note: it’s rather complex to detect what the expected indent is in block
|
||
// quotes and lists, so let’s only do directly in root for now.
|
||
if (!start || (parent && parent.type !== 'root')) {
|
||
return
|
||
}
|
||
|
||
const diff = start.column - 1
|
||
|
||
if (diff) {
|
||
file.message(
|
||
'Remove ' +
|
||
diff +
|
||
' ' +
|
||
plural('space', diff) +
|
||
' before this heading',
|
||
start
|
||
)
|
||
}
|
||
})
|
||
}
|
||
)
|
||
|
||
export default remarkLintNoHeadingIndent
|