Skip to content

Commit

Permalink
Add support for passing severities
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
wooorm committed Aug 15, 2016
1 parent 9bdd69e commit 77709f5
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 29 deletions.
29 changes: 28 additions & 1 deletion doc/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This document describes all (57)
available rules, what they check for, examples of
what they warn for, and how to fix their warnings.

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

```json
Expand All @@ -23,6 +23,33 @@ are supported in configuration objects:
}
```

Additionally, each rule can be configured with a severity
instead of a boolean as well. The following is handled the
same as passing `false`:

```json
{
"final-newline": [0]
}
```

...and passing `[1]` is as passing `true`. To trigger an
error instead of a warning, pass `2`:

```json
{
"final-newline": [2]
}
```

It’s also possible to pass both a severity and configuration:

```json
{
"maximum-line-length": [2, 70]
}
```

## Table of Contents

- [reset](#reset)
Expand Down
72 changes: 45 additions & 27 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,30 +51,17 @@ function lint(remark, options) {
var disable = [];
var known = [];
var pipeline = trough();
var setting;
var config;
var id;

/* Add each rule. */
for (id in rules) {
setting = settings[id];

known.push(id);
config = coerce(id, settings[id], reset);

if (setting != null) {
/* Pass turned on rules `undefined`. */
if (reset && setting === true) {
setting = undefined;
}

if (setting === false) {
setting = undefined;
disable.push(id);
} else {
enable.push(id);
}
}
(config[0] ? enable : disable).push(id);

pipeline.use(ruleFactory(id, rules[id], setting));
pipeline.use(ruleFactory(id, rules[id], config[0], config[1]));
}

/* Run all rules. */
Expand Down Expand Up @@ -155,11 +142,13 @@ function loadExternals(externals) {
*
* @param {string} id - Identifier.
* @param {Function} rule - Rule
* @param {number} severity - Severity.
* @param {*} options - Options for respective rule.
* @return {Function} - Trough ware.
*/
function ruleFactory(id, rule, options) {
function ruleFactory(id, rule, severity, options) {
var fn = wrapped(rule);
var fatal = severity === 2;

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

fn(ast, file, options, function (err) {
var messages = file.messages;
var message;

while (scope.index < messages.length) {
messages[scope.index].ruleId = id;
messages[scope.index].source = SOURCE;
message = messages[scope.index];
message.ruleId = id;
message.source = SOURCE;
message.fatal = fatal;

scope.index++;
}
Expand All @@ -182,13 +174,7 @@ function ruleFactory(id, rule, options) {
};
}

/**
* Helper to ensure ruleId’s are dash-cased instead of
* camel-cased.
*
* @param {Object} source - Original settings.
* @return {Object} - Dash-cased settings.
*/
/* Ensure ruleId’s are dash-cased. */
function decamelizeSettings(source) {
var result = {};
var key;
Expand All @@ -199,3 +185,35 @@ function decamelizeSettings(source) {

return result;
}

/* Coerce a value to a severity--options tuple. */
function coerce(name, value, reset) {
var def = reset ? 0 : 1;
var result;

if (value == null) {
result = [def];
} else if (typeof value === 'boolean') {
result = [value];
} else if (
typeof value === 'object' &&
(typeof value[0] === 'number' || typeof value[0] === 'boolean')
) {
result = value.concat();
} else {
result = [1, value];
}

if (typeof result[0] === 'boolean') {
result[0] = result[0] ? 1 : 0;
}

if (result[0] < 0 || result[0] > 2) {
throw new Error(
'Invalid severity `' + result[0] + '` for `' + name + '`, ' +
'expected 0, 1, or 2'
);
}

return result;
}
29 changes: 28 additions & 1 deletion script/build-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ var markdown = remark().use(toc);
'available rules, what they check for, examples of',
'what they warn for, and how to fix their warnings.',
'',
'Note: both camel-cased and dash-cases versions of rule id’s',
'Both camel-cased and dash-cases versions of rule id’s',
'are supported in configuration objects:',
'',
'```json',
Expand All @@ -121,6 +121,33 @@ var markdown = remark().use(toc);
'}',
'```',
'',
'Additionally, each rule can be configured with a severity',
'instead of a boolean as well. The following is handled the',
'same as passing `false`:',
'',
'```json',
'{',
' "final-newline": [0]',
'}',
'```',
'',
'...and passing `[1]` is as passing `true`. To trigger an',
'error instead of a warning, pass `2`:',
'',
'```json',
'{',
' "final-newline": [2]',
'}',
'```',
'',
'It’s also possible to pass both a severity and configuration:',
'',
'```json',
'{',
' "maximum-line-length": [2, 70]',
'}',
'```',
'',
'## Table of Contents',
'',
'## `reset`',
Expand Down
36 changes: 36 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,42 @@ test('core', function (t) {
});
});

t.test('should support a list with a severity', function (st) {
st.plan(3);

remark()
.use(lint, {reset: true, finalNewline: [2]})
.process('.', function (err, file) {
st.ifErr(err, 'should not fail');
st.equal(
file.messages.join(),
'1:1: Missing newline character at end of file',
'should trigger fatally (1)'
);
st.equal(file.messages[0].fatal, true, 'should trigger fatally (2)');
});
});

t.test('should fail on invalid severities', function (st) {
st.throws(
function () {
remark().use(lint, {finalNewline: [3]});
},
/^Error: Invalid severity `3` for `final-newline`, expected 0, 1, or 2$/,
'should throw when too high'
);

st.throws(
function () {
remark().use(lint, {finalNewline: [-1]});
},
/^Error: Invalid severity `-1` for `final-newline`, expected 0, 1, or 2$/,
'should throw too low'
);

st.end();
});

t.end();
});

Expand Down

1 comment on commit 77709f5

@kgryte
Copy link

@kgryte kgryte commented on 77709f5 Aug 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wooorm Awesome!

Please sign in to comment.