mirror of
https://github.com/remarkjs/remark-lint.git
synced 2024-09-11 19:57:15 +03:00
Update support for configuration comments
* Add a new `ignore` keyword which ignores warnings in the following node; * Externalise `lib/filter` to `remark-message-control`.
This commit is contained in:
parent
b6309f0c09
commit
870cb99a3e
@ -11,13 +11,15 @@
|
||||
],
|
||||
"repository": "wooorm/remark-lint",
|
||||
"dependencies": {
|
||||
"sindresorhus/plur": "^2.0.0",
|
||||
"wooorm/remark-range": "^2.0.0",
|
||||
"sindresorhus/decamelize": "^1.0.0",
|
||||
"wooorm/mdast-util-heading-style": "^1.0.0",
|
||||
"wooorm/mdast-util-position": "^1.0.0",
|
||||
"wooorm/mdast-util-to-string": "^1.0.0",
|
||||
"eush77/npm-prefix": "^1.1.1",
|
||||
"sindresorhus/plur": "^2.0.0",
|
||||
"wooorm/remark-message-control": "^1.0.1",
|
||||
"wooorm/remark-range": "^2.0.0",
|
||||
"wooorm/unist-util-visit": "^1.0.0",
|
||||
"wooorm/mdast-zone": "^2.0.0",
|
||||
"wooorm/vfile-sort": "^1.0.0"
|
||||
},
|
||||
"scripts": [
|
||||
|
139
lib/filter.js
139
lib/filter.js
@ -1,139 +0,0 @@
|
||||
/**
|
||||
* @author Titus Wormer
|
||||
* @copyright 2015 Titus Wormer
|
||||
* @license MIT
|
||||
* @module remark:lint:filter
|
||||
* @fileoverview remark plug-in used internally by
|
||||
* remark-lint to filter ruleId’s by enabled and disabled
|
||||
* ranges, or by gaps.
|
||||
* @todo Externalise into its own repository.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
var position = require('mdast-util-position');
|
||||
var visit = require('unist-util-visit');
|
||||
|
||||
/**
|
||||
* Remove warnings which are disabled, or are in gaps.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
*/
|
||||
function transformer(ast, file) {
|
||||
var lastNode = ast.children[ast.children.length - 1];
|
||||
var gaps = [];
|
||||
var offset = 0;
|
||||
var isGap = false;
|
||||
var scope = file.namespace('remark-lint').ranges;
|
||||
|
||||
if (!file || !file.messages || !file.messages.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch a new position.
|
||||
*
|
||||
* @param {number?} [latest] - Last found position.
|
||||
*/
|
||||
function update(latest) {
|
||||
if (latest === undefined || latest === null) {
|
||||
isGap = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset > latest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isGap) {
|
||||
gaps.push({
|
||||
'start': offset,
|
||||
'end': latest
|
||||
});
|
||||
|
||||
isGap = false;
|
||||
}
|
||||
|
||||
offset = latest;
|
||||
}
|
||||
|
||||
visit(ast, function (node) {
|
||||
var start = position.start(node);
|
||||
var end = position.end(node);
|
||||
|
||||
update(start && start.offset);
|
||||
|
||||
if (!node.children) {
|
||||
update(end && end.offset);
|
||||
}
|
||||
});
|
||||
|
||||
if (offset === position.end(lastNode).offset) {
|
||||
update();
|
||||
update(file.toString().length - 1);
|
||||
}
|
||||
|
||||
file.messages = file.messages.filter(function (message) {
|
||||
var ranges = scope[message.ruleId];
|
||||
var index = ranges && ranges.length;
|
||||
var gapIndex = gaps.length;
|
||||
var length = -1;
|
||||
var pos;
|
||||
var range;
|
||||
|
||||
if (!message.line) {
|
||||
message.line = 1;
|
||||
}
|
||||
|
||||
if (!message.column) {
|
||||
message.column = 1;
|
||||
}
|
||||
|
||||
pos = file.positionToOffset(message);
|
||||
|
||||
while (gapIndex--) {
|
||||
if (
|
||||
gaps[gapIndex].start <= pos &&
|
||||
gaps[gapIndex].end > pos
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
while (--index > length) {
|
||||
range = ranges[index];
|
||||
|
||||
if (
|
||||
range.position.line < message.line ||
|
||||
(
|
||||
range.position.line === message.line &&
|
||||
range.position.column < message.column
|
||||
)
|
||||
) {
|
||||
return range.state === true;
|
||||
}
|
||||
}
|
||||
|
||||
/* xistanbul ignore next - Just to be safe */
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `transformer`.
|
||||
*
|
||||
* @return {Function} - See `transformer`.
|
||||
*/
|
||||
function attacher() {
|
||||
return transformer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = attacher;
|
160
lib/index.js
160
lib/index.js
@ -24,9 +24,8 @@ var SOURCE = 'remark-lint';
|
||||
var decamelize = require('decamelize');
|
||||
var sort = require('vfile-sort');
|
||||
var range = require('remark-range');
|
||||
var zone = require('mdast-zone');
|
||||
var control = require('remark-message-control');
|
||||
var internals = require('./rules');
|
||||
var filter = require('./filter');
|
||||
var npmPrefix = require('npm-prefix')();
|
||||
|
||||
/*
|
||||
@ -249,10 +248,13 @@ function decamelizeSettings(source) {
|
||||
*/
|
||||
function lint(remark, options) {
|
||||
var settings = decamelizeSettings(options || {});
|
||||
var reset = settings.reset;
|
||||
var rules = loadExternals(settings.external);
|
||||
var id;
|
||||
var reset = options && options.reset;
|
||||
var enable = [];
|
||||
var disable = [];
|
||||
var known = [];
|
||||
var setting;
|
||||
var id;
|
||||
|
||||
/*
|
||||
* Ensure offset information is added.
|
||||
@ -260,151 +262,47 @@ function lint(remark, options) {
|
||||
|
||||
remark.use(range);
|
||||
|
||||
/**
|
||||
* Get the latest state of a rule.
|
||||
*
|
||||
* @param {string} ruleId - Unique rule name.
|
||||
* @param {File} [file] - File (optional)
|
||||
*/
|
||||
function getState(ruleId, file) {
|
||||
var scope = file && file.namespace('remark-lint');
|
||||
var ranges = scope && scope.ranges && scope.ranges[ruleId];
|
||||
|
||||
if (ranges) {
|
||||
return ranges[ranges.length - 1].state;
|
||||
}
|
||||
|
||||
setting = settings[ruleId];
|
||||
|
||||
if (setting === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !reset || (setting !== null && setting !== undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store settings on `file`.
|
||||
*
|
||||
* @param {File} file - Virtual file.
|
||||
*/
|
||||
function store(file) {
|
||||
var scope = file.namespace('remark-lint');
|
||||
var ranges = scope.ranges;
|
||||
var ruleId;
|
||||
|
||||
if (!ranges) {
|
||||
ranges = {};
|
||||
|
||||
for (ruleId in rules) {
|
||||
ranges[ruleId] = [{
|
||||
'state': getState(ruleId),
|
||||
'position': {
|
||||
'line': 0,
|
||||
'column': 0
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
scope.ranges = ranges;
|
||||
}
|
||||
}
|
||||
|
||||
remark.use(function () {
|
||||
return function (ast, file) {
|
||||
store(file);
|
||||
};
|
||||
});
|
||||
|
||||
/*
|
||||
* Add each rule as a seperate plugin.
|
||||
*/
|
||||
|
||||
for (id in rules) {
|
||||
remark.use(attachFactory(id, rules[id], settings[id]));
|
||||
setting = settings[id];
|
||||
|
||||
known.push(id);
|
||||
|
||||
if (!(setting === null || setting === undefined)) {
|
||||
if (setting === false) {
|
||||
disable.push(id);
|
||||
} else {
|
||||
enable.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
remark.use(attachFactory(id, rules[id], setting));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a rule.
|
||||
*
|
||||
* @param {VFile} file - Virtual file.
|
||||
* @param {Object} marker - Marker context.
|
||||
* @param {string} type - Type to toggle to.
|
||||
* @param {*} ruleId - Rule to toggle.
|
||||
*/
|
||||
function toggle(file, marker, type, ruleId) {
|
||||
var scope = file.namespace('remark-lint');
|
||||
var markers;
|
||||
var currentState;
|
||||
var previousState;
|
||||
|
||||
if (!(ruleId in rules)) {
|
||||
file.fail('Unknown rule: cannot ' + type + ' `\'' + ruleId + '\'`', marker.node);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
markers = scope.ranges[ruleId];
|
||||
|
||||
previousState = getState(ruleId, file);
|
||||
currentState = type === 'enable';
|
||||
|
||||
if (currentState !== previousState) {
|
||||
markers.push({
|
||||
'state': currentState,
|
||||
'position': marker.node.position.start
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a new-found marker.
|
||||
*
|
||||
* @param {Object} marker - Marker context.
|
||||
* @param {Object} parser - Parser instance.
|
||||
*/
|
||||
function onparse(marker, parser) {
|
||||
var file = parser.file;
|
||||
var attributes = marker.attributes.split(' ');
|
||||
var type = attributes[0];
|
||||
var ids = attributes.slice(1);
|
||||
var length = ids.length;
|
||||
var index = -1;
|
||||
|
||||
if (type !== 'disable' && type !== 'enable') {
|
||||
file.fail('Unknown lint keyword `' + type + '`: use either `\'enable\'` or `\'disable\'`', marker.node);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
store(file);
|
||||
|
||||
while (++index < length) {
|
||||
toggle(file, marker, type, ids[index]);
|
||||
}
|
||||
}
|
||||
|
||||
remark.use(zone({
|
||||
'name': 'lint',
|
||||
'onparse': onparse
|
||||
}));
|
||||
|
||||
/*
|
||||
* Filter.
|
||||
* Allow comments to toggle messages.
|
||||
*/
|
||||
|
||||
remark.use(filter);
|
||||
remark.use(control, {
|
||||
'name': 'lint',
|
||||
'source': SOURCE,
|
||||
'reset': reset,
|
||||
'known': known,
|
||||
'enable': enable,
|
||||
'disable': disable
|
||||
});
|
||||
|
||||
/**
|
||||
* Transformer sort messages.
|
||||
*
|
||||
* @param {Node} node - Syntax tree.
|
||||
* @param {VFile} file - Virtual file.
|
||||
* @param {Function} next - Completion handler.
|
||||
*/
|
||||
return function (node, file, next) {
|
||||
return function (node, file) {
|
||||
sort(file);
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,13 @@
|
||||
"author": "Titus Wormer <tituswormer@gmail.com>",
|
||||
"dependencies": {
|
||||
"decamelize": "^1.0.0",
|
||||
"remark-range": "^2.0.0",
|
||||
"mdast-util-heading-style": "^1.0.0",
|
||||
"mdast-util-position": "^1.0.0",
|
||||
"mdast-util-to-string": "^1.0.0",
|
||||
"mdast-zone": "^2.0.0",
|
||||
"npm-prefix": "^1.1.1",
|
||||
"plur": "^2.0.0",
|
||||
"remark-message-control": "^1.0.1",
|
||||
"remark-range": "^2.0.0",
|
||||
"unist-util-visit": "^1.0.0",
|
||||
"vfile-sort": "^1.0.0"
|
||||
},
|
||||
|
@ -114,8 +114,10 @@ markdown code. Read more about the latter on [**remark**’s
|
||||
readme][remark-process].
|
||||
|
||||
In addition, you can also provide configuration comments to turn a rule
|
||||
on or off inside a file (note that you cannot change what a setting, such as
|
||||
`maximum-line-length`, you’re either enabling or disabling warnings).
|
||||
on or off inside a file. Note that you cannot change what a setting,
|
||||
such as `maximum-line-length`, checks for, as you’re either enabling
|
||||
or disabling warnings). Read more about configuration comments in
|
||||
[**remark-message-control**][message-control]s documentation.
|
||||
|
||||
The following file will warn twice for the duplicate headings:
|
||||
|
||||
@ -234,3 +236,5 @@ excluding `remark-lint-no-` or `remark-lint-`
|
||||
[remark-process]: https://github.com/wooorm/remark#remarkprocessvalue-options-done
|
||||
|
||||
[linter-markdown]: https://atom.io/packages/linter-markdown
|
||||
|
||||
[message-control]: https://github.com/wooorm/remark-message-control#markers
|
||||
|
@ -357,7 +357,7 @@ describe('Comments', function () {
|
||||
|
||||
describe('Invalid comments', function () {
|
||||
assertFile('comments-invalid-keyword.md', [
|
||||
'comments-invalid-keyword.md:3:1-3:20: Unknown lint keyword `foo`: use either `\'enable\'` or `\'disable\'`'
|
||||
'comments-invalid-keyword.md:3:1-3:20: Unknown keyword `foo`: expected `\'enable\'`, `\'disable\'`, or `\'ignore\'`'
|
||||
], null, {
|
||||
'reset': true
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user