Skip to content

Commit 77709f5

Browse files
committed
Add support for passing severities
Previously, messages could be either turned on (as warnings), or turned off. This update adds support for setting these through an integer (`1` and `0` respectivly), in array form: ```js remark().use(lint, {finalNewline:[0]}); ``` Additionally, the integer `2` can be passed to turn a message into a fatal error: ```js remark().use(lint, {maximumLineLength: [2, 72]}); ``` Closes GH-65.
1 parent 9bdd69e commit 77709f5

File tree

4 files changed

+137
-29
lines changed

4 files changed

+137
-29
lines changed

doc/rules.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This document describes all (57)
66
available rules, what they check for, examples of
77
what they warn for, and how to fix their warnings.
88

9-
Note: both camel-cased and dash-cases versions of rule id’s
9+
Both camel-cased and dash-cases versions of rule id’s
1010
are supported in configuration objects:
1111

1212
```json
@@ -23,6 +23,33 @@ are supported in configuration objects:
2323
}
2424
```
2525

26+
Additionally, each rule can be configured with a severity
27+
instead of a boolean as well. The following is handled the
28+
same as passing `false`:
29+
30+
```json
31+
{
32+
"final-newline": [0]
33+
}
34+
```
35+
36+
...and passing `[1]` is as passing `true`. To trigger an
37+
error instead of a warning, pass `2`:
38+
39+
```json
40+
{
41+
"final-newline": [2]
42+
}
43+
```
44+
45+
It’s also possible to pass both a severity and configuration:
46+
47+
```json
48+
{
49+
"maximum-line-length": [2, 70]
50+
}
51+
```
52+
2653
## Table of Contents
2754

2855
- [reset](#reset)

lib/index.js

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -51,30 +51,17 @@ function lint(remark, options) {
5151
var disable = [];
5252
var known = [];
5353
var pipeline = trough();
54-
var setting;
54+
var config;
5555
var id;
5656

5757
/* Add each rule. */
5858
for (id in rules) {
59-
setting = settings[id];
60-
6159
known.push(id);
60+
config = coerce(id, settings[id], reset);
6261

63-
if (setting != null) {
64-
/* Pass turned on rules `undefined`. */
65-
if (reset && setting === true) {
66-
setting = undefined;
67-
}
68-
69-
if (setting === false) {
70-
setting = undefined;
71-
disable.push(id);
72-
} else {
73-
enable.push(id);
74-
}
75-
}
62+
(config[0] ? enable : disable).push(id);
7663

77-
pipeline.use(ruleFactory(id, rules[id], setting));
64+
pipeline.use(ruleFactory(id, rules[id], config[0], config[1]));
7865
}
7966

8067
/* Run all rules. */
@@ -155,11 +142,13 @@ function loadExternals(externals) {
155142
*
156143
* @param {string} id - Identifier.
157144
* @param {Function} rule - Rule
145+
* @param {number} severity - Severity.
158146
* @param {*} options - Options for respective rule.
159147
* @return {Function} - Trough ware.
160148
*/
161-
function ruleFactory(id, rule, options) {
149+
function ruleFactory(id, rule, severity, options) {
162150
var fn = wrapped(rule);
151+
var fatal = severity === 2;
163152

164153
return function (ast, file, next) {
165154
var scope = file.namespace('remark-lint');
@@ -169,10 +158,13 @@ function ruleFactory(id, rule, options) {
169158

170159
fn(ast, file, options, function (err) {
171160
var messages = file.messages;
161+
var message;
172162

173163
while (scope.index < messages.length) {
174-
messages[scope.index].ruleId = id;
175-
messages[scope.index].source = SOURCE;
164+
message = messages[scope.index];
165+
message.ruleId = id;
166+
message.source = SOURCE;
167+
message.fatal = fatal;
176168

177169
scope.index++;
178170
}
@@ -182,13 +174,7 @@ function ruleFactory(id, rule, options) {
182174
};
183175
}
184176

185-
/**
186-
* Helper to ensure ruleId’s are dash-cased instead of
187-
* camel-cased.
188-
*
189-
* @param {Object} source - Original settings.
190-
* @return {Object} - Dash-cased settings.
191-
*/
177+
/* Ensure ruleId’s are dash-cased. */
192178
function decamelizeSettings(source) {
193179
var result = {};
194180
var key;
@@ -199,3 +185,35 @@ function decamelizeSettings(source) {
199185

200186
return result;
201187
}
188+
189+
/* Coerce a value to a severity--options tuple. */
190+
function coerce(name, value, reset) {
191+
var def = reset ? 0 : 1;
192+
var result;
193+
194+
if (value == null) {
195+
result = [def];
196+
} else if (typeof value === 'boolean') {
197+
result = [value];
198+
} else if (
199+
typeof value === 'object' &&
200+
(typeof value[0] === 'number' || typeof value[0] === 'boolean')
201+
) {
202+
result = value.concat();
203+
} else {
204+
result = [1, value];
205+
}
206+
207+
if (typeof result[0] === 'boolean') {
208+
result[0] = result[0] ? 1 : 0;
209+
}
210+
211+
if (result[0] < 0 || result[0] > 2) {
212+
throw new Error(
213+
'Invalid severity `' + result[0] + '` for `' + name + '`, ' +
214+
'expected 0, 1, or 2'
215+
);
216+
}
217+
218+
return result;
219+
}

script/build-docs.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ var markdown = remark().use(toc);
104104
'available rules, what they check for, examples of',
105105
'what they warn for, and how to fix their warnings.',
106106
'',
107-
'Note: both camel-cased and dash-cases versions of rule id’s',
107+
'Both camel-cased and dash-cases versions of rule id’s',
108108
'are supported in configuration objects:',
109109
'',
110110
'```json',
@@ -121,6 +121,33 @@ var markdown = remark().use(toc);
121121
'}',
122122
'```',
123123
'',
124+
'Additionally, each rule can be configured with a severity',
125+
'instead of a boolean as well. The following is handled the',
126+
'same as passing `false`:',
127+
'',
128+
'```json',
129+
'{',
130+
' "final-newline": [0]',
131+
'}',
132+
'```',
133+
'',
134+
'...and passing `[1]` is as passing `true`. To trigger an',
135+
'error instead of a warning, pass `2`:',
136+
'',
137+
'```json',
138+
'{',
139+
' "final-newline": [2]',
140+
'}',
141+
'```',
142+
'',
143+
'It’s also possible to pass both a severity and configuration:',
144+
'',
145+
'```json',
146+
'{',
147+
' "maximum-line-length": [2, 70]',
148+
'}',
149+
'```',
150+
'',
124151
'## Table of Contents',
125152
'',
126153
'## `reset`',

test/index.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,42 @@ test('core', function (t) {
8585
});
8686
});
8787

88+
t.test('should support a list with a severity', function (st) {
89+
st.plan(3);
90+
91+
remark()
92+
.use(lint, {reset: true, finalNewline: [2]})
93+
.process('.', function (err, file) {
94+
st.ifErr(err, 'should not fail');
95+
st.equal(
96+
file.messages.join(),
97+
'1:1: Missing newline character at end of file',
98+
'should trigger fatally (1)'
99+
);
100+
st.equal(file.messages[0].fatal, true, 'should trigger fatally (2)');
101+
});
102+
});
103+
104+
t.test('should fail on invalid severities', function (st) {
105+
st.throws(
106+
function () {
107+
remark().use(lint, {finalNewline: [3]});
108+
},
109+
/^Error: Invalid severity `3` for `final-newline`, expected 0, 1, or 2$/,
110+
'should throw when too high'
111+
);
112+
113+
st.throws(
114+
function () {
115+
remark().use(lint, {finalNewline: [-1]});
116+
},
117+
/^Error: Invalid severity `-1` for `final-newline`, expected 0, 1, or 2$/,
118+
'should throw too low'
119+
);
120+
121+
st.end();
122+
});
123+
88124
t.end();
89125
});
90126

0 commit comments

Comments
 (0)