/
index.js
146 lines (138 loc) · 3.52 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* @author Titus Wormer
* @copyright 2015 Titus Wormer
* @license MIT
* @module fenced-code-marker
* @fileoverview
* Warn for violating fenced code markers.
*
* Options: `` '`' ``, `'~'`, or `'consistent'`, default: `'consistent'`.
*
* `'consistent'` detects the first used fenced code marker style and warns
* when subsequent fenced code blocks use different styles.
*
* ## Fix
*
* [`remark-stringify`](https://github.com/remarkjs/remark/tree/HEAD/packages/remark-stringify)
* formats fences using ``'`'`` (grave accent) by default.
* Pass
* [`fence: '~'`](https://github.com/remarkjs/remark/tree/HEAD/packages/remark-stringify#optionsfence)
* to use `~` (tilde) instead.
*
* See [Using remark to fix your Markdown](https://github.com/remarkjs/remark-lint#using-remark-to-fix-your-markdown)
* on how to automatically fix warnings for this rule.
*
* @example
* {"name": "ok.md"}
*
* Indented code blocks are not affected by this rule:
*
* bravo()
*
* @example
* {"name": "ok.md", "setting": "`"}
*
* ```alpha
* bravo()
* ```
*
* ```
* charlie()
* ```
*
* @example
* {"name": "ok.md", "setting": "~"}
*
* ~~~alpha
* bravo()
* ~~~
*
* ~~~
* charlie()
* ~~~
*
* @example
* {"name": "not-ok-consistent-tick.md", "label": "input"}
*
* ```alpha
* bravo()
* ```
*
* ~~~
* charlie()
* ~~~
*
* @example
* {"name": "not-ok-consistent-tick.md", "label": "output"}
*
* 5:1-7:4: Fenced code should use `` ` `` as a marker
*
* @example
* {"name": "not-ok-consistent-tilde.md", "label": "input"}
*
* ~~~alpha
* bravo()
* ~~~
*
* ```
* charlie()
* ```
*
* @example
* {"name": "not-ok-consistent-tilde.md", "label": "output"}
*
* 5:1-7:4: Fenced code should use `~` as a marker
*
* @example
* {"name": "not-ok-incorrect.md", "setting": "💩", "label": "output", "positionless": true}
*
* 1:1: Incorrect fenced code marker `💩`: use either `'consistent'`, `` '`' ``, or `'~'`
*/
/**
* @typedef {import('mdast').Root} Root
* @typedef {'~'|'`'} Marker
* @typedef {'consistent'|Marker} Options
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {pointStart} from 'unist-util-position'
const remarkLintFencedCodeMarker = lintRule(
{
origin: 'remark-lint:fenced-code-marker',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-fenced-code-marker#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 'consistent') => {
const contents = String(file)
if (option !== 'consistent' && option !== '~' && option !== '`') {
file.fail(
'Incorrect fenced code marker `' +
option +
"`: use either `'consistent'`, `` '`' ``, or `'~'`"
)
}
visit(tree, 'code', (node) => {
const start = pointStart(node).offset
if (typeof start === 'number') {
const marker = contents
.slice(start, start + 4)
.replace(/^\s+/, '')
.charAt(0)
// Ignore unfenced code blocks.
if (marker === '~' || marker === '`') {
if (option === 'consistent') {
option = marker
} else if (marker !== option) {
file.message(
'Fenced code should use `' +
(option === '~' ? option : '` ` `') +
'` as a marker',
node
)
}
}
}
})
}
)
export default remarkLintFencedCodeMarker