mirror of
https://github.com/remarkjs/remark-lint.git
synced 2024-08-17 07:40:31 +03:00
Refactor code-style to use xo
This commit is contained in:
parent
d272ff257b
commit
60907ad17e
@ -2,14 +2,8 @@ root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{json,remarkrc}]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
@ -1,3 +0,0 @@
|
||||
coverage/
|
||||
remark-lint.js
|
||||
remark-lint.min.js
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
"quotes": [2, "single"]
|
||||
}
|
||||
}
|
34
.jscs.json
34
.jscs.json
@ -1,34 +0,0 @@
|
||||
{
|
||||
"excludeFiles": [
|
||||
"coverage/",
|
||||
"node_modules/",
|
||||
"remark-lint.js",
|
||||
"remark-lint.min.js"
|
||||
],
|
||||
"preset": "crockford",
|
||||
"requireMultipleVarDecl": false,
|
||||
"requireVarDeclFirst": false,
|
||||
"disallowDanglingUnderscores": false,
|
||||
"maximumLineLength": false,
|
||||
"requireQuotedKeysInObjects": true,
|
||||
"disallowKeywords": [
|
||||
"with"
|
||||
],
|
||||
"jsDoc": {
|
||||
"checkAnnotations": "jsdoc3",
|
||||
"checkParamExistence": true,
|
||||
"checkParamNames": true,
|
||||
"checkRedundantAccess": true,
|
||||
"checkRedundantParams": true,
|
||||
"checkRedundantReturns": true,
|
||||
"checkReturnTypes": true,
|
||||
"checkTypes": "strictNativeCase",
|
||||
"enforceExistence": true,
|
||||
"requireHyphenBeforeDescription": true,
|
||||
"requireNewlineAfterDescription": true,
|
||||
"requireParamDescription": true,
|
||||
"requireParamTypes": true,
|
||||
"requireReturnDescription": true,
|
||||
"requireReturnTypes": true
|
||||
}
|
||||
}
|
@ -1,4 +1 @@
|
||||
# `node_modules/` is already ignored.
|
||||
|
||||
# Do not process fixtures.
|
||||
test
|
||||
|
17
.remarkrc
17
.remarkrc
@ -1,17 +0,0 @@
|
||||
{
|
||||
"output": true,
|
||||
"plugins": {
|
||||
"comment-config": null,
|
||||
"github": null,
|
||||
"toc": {
|
||||
"tight": true
|
||||
},
|
||||
"./": {
|
||||
"no-missing-blank-lines": false
|
||||
},
|
||||
"validate-links": null
|
||||
},
|
||||
"settings": {
|
||||
"bullet": "*"
|
||||
}
|
||||
}
|
294
lib/index.js
294
lib/index.js
@ -11,16 +11,7 @@
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
|
||||
var SOURCE = 'remark-lint';
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var decamelize = require('decamelize');
|
||||
var sort = require('vfile-sort');
|
||||
var control = require('remark-message-control');
|
||||
@ -29,42 +20,89 @@ var trough = require('trough');
|
||||
var wrapped = require('wrapped');
|
||||
var internals = require('./rules');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = lint;
|
||||
|
||||
/* Constants. */
|
||||
var SOURCE = 'remark-lint';
|
||||
|
||||
/**
|
||||
* Factory to create a plugin from a rule.
|
||||
* Lint attacher.
|
||||
*
|
||||
* By default, all rules are turned on unless explicitly
|
||||
* set to `false`. When `reset: true`, the opposite is
|
||||
* true: all rules are turned off, unless when given
|
||||
* a non-nully and non-false value.
|
||||
*
|
||||
* @example
|
||||
* attachFactory('foo', console.log, false)() // null
|
||||
* attachFactory('foo', console.log, {})() // plugin
|
||||
* var processor = lint(remark, {
|
||||
* html: false // Ignore HTML warnings.
|
||||
* });
|
||||
*
|
||||
* @param {string} id - Identifier.
|
||||
* @param {Function} rule - Rule
|
||||
* @param {*} options - Options for respective rule.
|
||||
* @return {Function} - Trough ware.
|
||||
* @param {Remark} remark - Host object.
|
||||
* @param {Object?} options - Hash of rule names mapping to
|
||||
* rule options.
|
||||
*/
|
||||
function ruleFactory(id, rule, options) {
|
||||
var fn = wrapped(rule);
|
||||
function lint(remark, options) {
|
||||
var settings = decamelizeSettings(options || {});
|
||||
var rules = loadExternals(settings.external);
|
||||
var reset = options && options.reset;
|
||||
var enable = [];
|
||||
var disable = [];
|
||||
var known = [];
|
||||
var pipeline = trough();
|
||||
var setting;
|
||||
var id;
|
||||
|
||||
return function (ast, file, next) {
|
||||
var scope = file.namespace('remark-lint');
|
||||
/* Add each rule. */
|
||||
for (id in rules) {
|
||||
setting = settings[id];
|
||||
|
||||
/* Track new messages per file. */
|
||||
if (scope.index === undefined || scope.index === null) {
|
||||
scope.index = file.messages.length;
|
||||
}
|
||||
known.push(id);
|
||||
|
||||
fn(ast, file, options, function (err) {
|
||||
var messages = file.messages;
|
||||
if (setting != null) {
|
||||
/* Pass turned on rules `undefined`. */
|
||||
if (reset && setting === true) {
|
||||
setting = undefined;
|
||||
}
|
||||
|
||||
while (scope.index < messages.length) {
|
||||
messages[scope.index].ruleId = id;
|
||||
messages[scope.index].source = SOURCE;
|
||||
|
||||
scope.index++;
|
||||
}
|
||||
|
||||
next(err);
|
||||
});
|
||||
if (setting === false) {
|
||||
setting = undefined;
|
||||
disable.push(id);
|
||||
} else {
|
||||
enable.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.use(ruleFactory(id, rules[id], setting));
|
||||
}
|
||||
|
||||
/* Run all rules. */
|
||||
remark.use(function () {
|
||||
return function (node, file, next) {
|
||||
pipeline.run(node, file, next);
|
||||
};
|
||||
});
|
||||
|
||||
/* Allow comments to toggle messages. */
|
||||
remark.use(control, {
|
||||
name: 'lint',
|
||||
source: SOURCE,
|
||||
reset: reset,
|
||||
known: known,
|
||||
enable: enable,
|
||||
disable: disable
|
||||
});
|
||||
|
||||
/**
|
||||
* Transformer to sort messages.
|
||||
*
|
||||
* @param {Node} node - Syntax tree.
|
||||
* @param {VFile} file - Virtual file.
|
||||
*/
|
||||
return function (node, file) {
|
||||
sort(file);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,31 +119,69 @@ function ruleFactory(id, rule, options) {
|
||||
* @throws {Error} - When an external cannot be resolved.
|
||||
*/
|
||||
function loadExternals(externals) {
|
||||
var index = -1;
|
||||
var rules = {};
|
||||
var external;
|
||||
var ruleId;
|
||||
var mapping = externals ? externals.concat() : [];
|
||||
var length;
|
||||
var index = -1;
|
||||
var rules = {};
|
||||
var external;
|
||||
var ruleId;
|
||||
var mapping = externals ? externals.concat() : [];
|
||||
var length;
|
||||
|
||||
mapping.push(internals);
|
||||
length = mapping.length;
|
||||
mapping.push(internals);
|
||||
length = mapping.length;
|
||||
|
||||
while (++index < length) {
|
||||
external = mapping[index];
|
||||
while (++index < length) {
|
||||
external = mapping[index];
|
||||
|
||||
if (typeof external === 'string') {
|
||||
external = loadPlugin(external, {
|
||||
prefix: 'remark-lint-'
|
||||
});
|
||||
}
|
||||
|
||||
for (ruleId in external) {
|
||||
rules[ruleId] = external[ruleId];
|
||||
}
|
||||
if (typeof external === 'string') {
|
||||
external = loadPlugin(external, {
|
||||
prefix: 'remark-lint-'
|
||||
});
|
||||
}
|
||||
|
||||
return rules;
|
||||
for (ruleId in external) {
|
||||
rules[ruleId] = external[ruleId];
|
||||
}
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory to create a plugin from a rule.
|
||||
*
|
||||
* @example
|
||||
* attachFactory('foo', console.log, false)() // null
|
||||
* attachFactory('foo', console.log, {})() // plugin
|
||||
*
|
||||
* @param {string} id - Identifier.
|
||||
* @param {Function} rule - Rule
|
||||
* @param {*} options - Options for respective rule.
|
||||
* @return {Function} - Trough ware.
|
||||
*/
|
||||
function ruleFactory(id, rule, options) {
|
||||
var fn = wrapped(rule);
|
||||
|
||||
return function (ast, file, next) {
|
||||
var scope = file.namespace('remark-lint');
|
||||
|
||||
/* Track new messages per file. */
|
||||
if (scope.index === undefined || scope.index === null) {
|
||||
scope.index = file.messages.length;
|
||||
}
|
||||
|
||||
fn(ast, file, options, function (err) {
|
||||
var messages = file.messages;
|
||||
|
||||
while (scope.index < messages.length) {
|
||||
messages[scope.index].ruleId = id;
|
||||
messages[scope.index].source = SOURCE;
|
||||
|
||||
scope.index++;
|
||||
}
|
||||
|
||||
next(err);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,106 +192,12 @@ function loadExternals(externals) {
|
||||
* @return {Object} - Dash-cased settings.
|
||||
*/
|
||||
function decamelizeSettings(source) {
|
||||
var result = {};
|
||||
var key;
|
||||
var result = {};
|
||||
var key;
|
||||
|
||||
for (key in source) {
|
||||
result[decamelize(key, '-')] = source[key];
|
||||
}
|
||||
for (key in source) {
|
||||
result[decamelize(key, '-')] = source[key];
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lint attacher.
|
||||
*
|
||||
* By default, all rules are turned on unless explicitly
|
||||
* set to `false`. When `reset: true`, the opposite is
|
||||
* true: all rules are turned off, unless when given
|
||||
* a non-nully and non-false value.
|
||||
*
|
||||
* @example
|
||||
* var processor = lint(remark, {
|
||||
* 'html': false // Ignore HTML warnings.
|
||||
* });
|
||||
*
|
||||
* @param {Remark} remark - Host object.
|
||||
* @param {Object?} options - Hash of rule names mapping to
|
||||
* rule options.
|
||||
*/
|
||||
function lint(remark, options) {
|
||||
var settings = decamelizeSettings(options || {});
|
||||
var rules = loadExternals(settings.external);
|
||||
var reset = options && options.reset;
|
||||
var enable = [];
|
||||
var disable = [];
|
||||
var known = [];
|
||||
var pipeline = trough();
|
||||
var setting;
|
||||
var id;
|
||||
|
||||
/*
|
||||
* Add each rule as a seperate plugin.
|
||||
*/
|
||||
|
||||
for (id in rules) {
|
||||
setting = settings[id];
|
||||
|
||||
known.push(id);
|
||||
|
||||
if (!(setting === null || setting === undefined)) {
|
||||
/* Pass turned on rules `undefined`. */
|
||||
if (reset && setting === true) {
|
||||
setting = undefined;
|
||||
}
|
||||
|
||||
if (setting === false) {
|
||||
setting = undefined;
|
||||
disable.push(id);
|
||||
} else {
|
||||
enable.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.use(ruleFactory(id, rules[id], setting));
|
||||
}
|
||||
|
||||
/*
|
||||
* Run all rules.
|
||||
*/
|
||||
|
||||
remark.use(function () {
|
||||
return function (node, file, next) {
|
||||
pipeline.run(node, file, next);
|
||||
};
|
||||
});
|
||||
|
||||
/*
|
||||
* Allow comments to toggle messages.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
return function (node, file) {
|
||||
sort(file);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = lint;
|
||||
|
@ -29,35 +29,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = blockquoteIndentation;
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var toString = require('mdast-util-to-string');
|
||||
var plural = require('plur');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/**
|
||||
* Get the indent of a blockquote.
|
||||
*
|
||||
* @param {Node} node - Node to test.
|
||||
* @return {number} - Indentation.
|
||||
*/
|
||||
function check(node) {
|
||||
var head = node.children[0];
|
||||
var indentation = position.start(head).column - position.start(node).column;
|
||||
var padding = toString(head).match(/^ +/);
|
||||
|
||||
if (padding) {
|
||||
indentation += padding[0].length;
|
||||
}
|
||||
|
||||
return indentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn when a blockquote has a too large or too small
|
||||
* indentation.
|
||||
@ -68,44 +48,53 @@ function check(node) {
|
||||
* indentation between a blockquote and its content.
|
||||
* When not a number, defaults to the first found
|
||||
* indentation.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function blockquoteIndentation(ast, file, preferred, done) {
|
||||
preferred = isNaN(preferred) || typeof preferred !== 'number' ? null : preferred;
|
||||
function blockquoteIndentation(ast, file, preferred) {
|
||||
preferred = isNaN(preferred) || typeof preferred !== 'number' ? null : preferred;
|
||||
|
||||
visit(ast, 'blockquote', function (node) {
|
||||
var indent;
|
||||
var diff;
|
||||
var word;
|
||||
visit(ast, 'blockquote', function (node) {
|
||||
var indent;
|
||||
var diff;
|
||||
var word;
|
||||
|
||||
if (position.generated(node) || !node.children.length) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node) || !node.children.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (preferred) {
|
||||
indent = check(node);
|
||||
diff = preferred - indent;
|
||||
word = diff > 0 ? 'Add' : 'Remove';
|
||||
if (preferred) {
|
||||
indent = check(node);
|
||||
diff = preferred - indent;
|
||||
word = diff > 0 ? 'Add' : 'Remove';
|
||||
|
||||
diff = Math.abs(diff);
|
||||
diff = Math.abs(diff);
|
||||
|
||||
if (diff !== 0) {
|
||||
file.warn(
|
||||
word + ' ' + diff + ' ' + plural('space', diff) +
|
||||
' between blockquote and content',
|
||||
position.start(node.children[0])
|
||||
);
|
||||
}
|
||||
} else {
|
||||
preferred = check(node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (diff !== 0) {
|
||||
file.warn(
|
||||
word + ' ' + diff + ' ' + plural('space', diff) +
|
||||
' between blockquote and content',
|
||||
position.start(node.children[0])
|
||||
);
|
||||
}
|
||||
} else {
|
||||
preferred = check(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
/**
|
||||
* Get the indent of a blockquote.
|
||||
*
|
||||
* @param {Node} node - Node to test.
|
||||
* @return {number} - Indentation.
|
||||
*/
|
||||
function check(node) {
|
||||
var head = node.children[0];
|
||||
var indentation = position.start(head).column - position.start(node).column;
|
||||
var padding = toString(head).match(/^ +/);
|
||||
|
||||
module.exports = blockquoteIndentation;
|
||||
if (padding) {
|
||||
indentation += padding[0].length;
|
||||
}
|
||||
|
||||
return indentation;
|
||||
}
|
||||
|
@ -21,19 +21,19 @@
|
||||
* @example
|
||||
* <!-- Note: the double guillemet (`»`) and middle-dots represent a tab -->
|
||||
*
|
||||
* <!-- Valid by default, `'consistent'`, or `{'checked': 'x'}` -->
|
||||
* <!-- Valid by default, `'consistent'`, or `{checked: 'x'}` -->
|
||||
* - [x] List item
|
||||
* - [x] List item
|
||||
*
|
||||
* <!-- Valid by default, `'consistent'`, or `{'checked': 'X'}` -->
|
||||
* <!-- Valid by default, `'consistent'`, or `{checked: 'X'}` -->
|
||||
* - [X] List item
|
||||
* - [X] List item
|
||||
*
|
||||
* <!-- Valid by default, `'consistent'`, or `{'unchecked': ' '}` -->
|
||||
* <!-- Valid by default, `'consistent'`, or `{unchecked: ' '}` -->
|
||||
* - [ ] List item
|
||||
* - [ ] List item
|
||||
*
|
||||
* <!-- Valid by default, `'consistent'`, or `{'unchecked': '»'}` -->
|
||||
* <!-- Valid by default, `'consistent'`, or `{unchecked: '»'}` -->
|
||||
* - [»···] List item
|
||||
* - [»···] List item
|
||||
*
|
||||
@ -46,32 +46,21 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var vfileLocation = require('vfile-location');
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = checkboxCharacterStyle;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
var CHECKED = {
|
||||
'x': true,
|
||||
'X': true
|
||||
};
|
||||
|
||||
var UNCHECKED = {
|
||||
' ': true,
|
||||
' ': true
|
||||
};
|
||||
/* Constants. */
|
||||
var CHECKED = {x: true, X: true};
|
||||
var UNCHECKED = {' ': true, '\t': true};
|
||||
|
||||
/**
|
||||
* Warn when list item checkboxes violate a given style.
|
||||
@ -82,107 +71,89 @@ var UNCHECKED = {
|
||||
* and `unchecked` properties, each set to null to default to
|
||||
* the first found style, or set to `'x'` or `'X'` for checked,
|
||||
* or `' '` (space) or `'\t'` (tab) for unchecked.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function checkboxCharacterStyle(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
function checkboxCharacterStyle(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
|
||||
if (preferred === 'consistent' || typeof preferred !== 'object') {
|
||||
preferred = {};
|
||||
}
|
||||
if (preferred === 'consistent' || typeof preferred !== 'object') {
|
||||
preferred = {};
|
||||
}
|
||||
|
||||
if (!preferred.unchecked) {
|
||||
preferred.unchecked = null;
|
||||
}
|
||||
if (!preferred.unchecked) {
|
||||
preferred.unchecked = null;
|
||||
}
|
||||
|
||||
if (!preferred.checked) {
|
||||
preferred.checked = null;
|
||||
}
|
||||
if (!preferred.checked) {
|
||||
preferred.checked = null;
|
||||
}
|
||||
|
||||
if (
|
||||
preferred.unchecked !== null &&
|
||||
UNCHECKED[preferred.unchecked] !== true
|
||||
) {
|
||||
file.fail(
|
||||
'Invalid unchecked checkbox marker `' +
|
||||
preferred.unchecked +
|
||||
'`: use either `\'\\t\'`, or `\' \'`'
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
preferred.checked !== null &&
|
||||
CHECKED[preferred.checked] !== true
|
||||
) {
|
||||
file.fail(
|
||||
'Invalid checked checkbox marker `' +
|
||||
preferred.checked +
|
||||
'`: use either `\'x\'`, or `\'X\'`'
|
||||
);
|
||||
}
|
||||
|
||||
visit(ast, 'listItem', function (node) {
|
||||
var type;
|
||||
var initial;
|
||||
var final;
|
||||
var stop;
|
||||
var value;
|
||||
var style;
|
||||
var character;
|
||||
|
||||
/* Exit early for items without checkbox. */
|
||||
if (
|
||||
preferred.unchecked !== null &&
|
||||
UNCHECKED[preferred.unchecked] !== true
|
||||
node.checked !== Boolean(node.checked) ||
|
||||
position.generated(node)
|
||||
) {
|
||||
file.fail(
|
||||
'Invalid unchecked checkbox marker `' +
|
||||
preferred.unchecked +
|
||||
'`: use either `\'\\t\'`, or `\' \'`'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
preferred.checked !== null &&
|
||||
CHECKED[preferred.checked] !== true
|
||||
) {
|
||||
file.fail(
|
||||
'Invalid checked checkbox marker `' +
|
||||
preferred.checked +
|
||||
'`: use either `\'x\'`, or `\'X\'`'
|
||||
);
|
||||
type = node.checked ? 'checked' : 'unchecked';
|
||||
|
||||
initial = start(node).offset;
|
||||
final = (node.children.length ? start(node.children[0]) : end(node)).offset;
|
||||
|
||||
/* For a checkbox to be parsed, it must be followed
|
||||
* by a white space. */
|
||||
value = contents.slice(initial, final).trimRight().slice(0, -1);
|
||||
|
||||
/* The checkbox character is behind a square
|
||||
* bracket. */
|
||||
character = value.charAt(value.length - 1);
|
||||
style = preferred[type];
|
||||
|
||||
if (style === null) {
|
||||
preferred[type] = character;
|
||||
} else if (character !== style) {
|
||||
stop = initial + value.length;
|
||||
|
||||
file.warn(
|
||||
type.charAt(0).toUpperCase() + type.slice(1) +
|
||||
' checkboxes should use `' + style + '` as a marker',
|
||||
{
|
||||
start: location.toPosition(stop - 1),
|
||||
end: location.toPosition(stop)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
visit(ast, 'listItem', function (node) {
|
||||
var type;
|
||||
var initial;
|
||||
var final;
|
||||
var stop;
|
||||
var value;
|
||||
var style;
|
||||
var character;
|
||||
|
||||
/*
|
||||
* Exit early for items without checkbox.
|
||||
*/
|
||||
|
||||
if (
|
||||
node.checked !== Boolean(node.checked) ||
|
||||
position.generated(node)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
type = node.checked ? 'checked' : 'unchecked';
|
||||
|
||||
initial = start(node).offset;
|
||||
final = (node.children.length ? start(node.children[0]) : end(node)).offset;
|
||||
|
||||
/*
|
||||
* For a checkbox to be parsed, it must be followed
|
||||
* by a white space.
|
||||
*/
|
||||
|
||||
value = contents.slice(initial, final).trimRight().slice(0, -1);
|
||||
|
||||
/*
|
||||
* The checkbox character is behind a square
|
||||
* bracket.
|
||||
*/
|
||||
|
||||
character = value.charAt(value.length - 1);
|
||||
style = preferred[type];
|
||||
|
||||
if (style === null) {
|
||||
preferred[type] = character;
|
||||
} else if (character !== style) {
|
||||
stop = initial + value.length;
|
||||
|
||||
file.warn(
|
||||
type.charAt(0).toUpperCase() + type.slice(1) +
|
||||
' checkboxes should use `' + style + '` as a marker',
|
||||
{
|
||||
'start': location.toPosition(stop - 1),
|
||||
'end': location.toPosition(stop)
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = checkboxCharacterStyle;
|
||||
|
@ -21,20 +21,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var vfileLocation = require('vfile-location');
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = checkboxContentIndent;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
@ -44,59 +39,44 @@ var end = position.end;
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function checkboxContentIndent(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
function checkboxContentIndent(ast, file) {
|
||||
var contents = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
|
||||
visit(ast, 'listItem', function (node) {
|
||||
var initial;
|
||||
var final;
|
||||
var value;
|
||||
visit(ast, 'listItem', function (node) {
|
||||
var initial;
|
||||
var final;
|
||||
var value;
|
||||
|
||||
/*
|
||||
* Exit early for items without checkbox.
|
||||
*/
|
||||
/* Exit early for items without checkbox. */
|
||||
if (
|
||||
node.checked !== Boolean(node.checked) ||
|
||||
position.generated(node)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
node.checked !== Boolean(node.checked) ||
|
||||
position.generated(node)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
initial = start(node).offset;
|
||||
final = (node.children.length ? start(node.children[0]) : end(node)).offset;
|
||||
|
||||
initial = start(node).offset;
|
||||
final = (node.children.length ? start(node.children[0]) : end(node)).offset;
|
||||
while (/[^\S\n]/.test(contents.charAt(final))) {
|
||||
final++;
|
||||
}
|
||||
|
||||
while (/[^\S\n]/.test(contents.charAt(final))) {
|
||||
final++;
|
||||
}
|
||||
/* For a checkbox to be parsed, it must be followed
|
||||
* by a white space. */
|
||||
value = contents.slice(initial, final);
|
||||
|
||||
/*
|
||||
* For a checkbox to be parsed, it must be followed
|
||||
* by a white space.
|
||||
*/
|
||||
value = value.slice(value.indexOf(']') + 1);
|
||||
|
||||
value = contents.slice(initial, final);
|
||||
if (value.length === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
value = value.slice(value.indexOf(']') + 1);
|
||||
|
||||
if (value.length === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
file.warn('Checkboxes should be followed by a single character', {
|
||||
'start': location.toPosition(final - value.length + 1),
|
||||
'end': location.toPosition(final)
|
||||
});
|
||||
file.warn('Checkboxes should be followed by a single character', {
|
||||
start: location.toPosition(final - value.length + 1),
|
||||
end: location.toPosition(final)
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = checkboxContentIndent;
|
||||
|
@ -39,30 +39,22 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = codeBlockStyle;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
/*
|
||||
* Valid styles.
|
||||
*/
|
||||
|
||||
/* Valid styles. */
|
||||
var STYLES = {
|
||||
'null': true,
|
||||
'fenced': true,
|
||||
'indented': true
|
||||
null: true,
|
||||
fenced: true,
|
||||
indented: true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -74,63 +66,55 @@ var STYLES = {
|
||||
* code block style. Defaults to `'consistent'` when
|
||||
* not a a string. Otherwise, should be one of
|
||||
* `'fenced'` or `'indented'`.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function codeBlockStyle(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function codeBlockStyle(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid code block style `' + preferred + '`: use either `\'consistent\'`, `\'fenced\'`, or `\'indented\'`');
|
||||
done();
|
||||
return;
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid code block style `' + preferred + '`: use either `\'consistent\'`, `\'fenced\'`, or `\'indented\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'code', function (node) {
|
||||
var current = check(node);
|
||||
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the style of `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
* @return {string?} - `'fenced'`, `'indented'`, or
|
||||
* `null`.
|
||||
*/
|
||||
function check(node) {
|
||||
var initial = start(node).offset;
|
||||
var final = end(node).offset;
|
||||
if (!preferred) {
|
||||
preferred = current;
|
||||
} else if (preferred !== current) {
|
||||
file.warn('Code blocks should be ' + preferred, node);
|
||||
}
|
||||
});
|
||||
|
||||
if (position.generated(node)) {
|
||||
return null;
|
||||
}
|
||||
return;
|
||||
|
||||
if (
|
||||
node.lang ||
|
||||
/^\s*([~`])\1{2,}/.test(contents.slice(initial, final))
|
||||
) {
|
||||
return 'fenced';
|
||||
}
|
||||
/**
|
||||
* Get the style of `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
* @return {string?} - `'fenced'`, `'indented'`, or
|
||||
* `null`.
|
||||
*/
|
||||
function check(node) {
|
||||
var initial = start(node).offset;
|
||||
var final = end(node).offset;
|
||||
|
||||
return 'indented';
|
||||
if (position.generated(node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
visit(ast, 'code', function (node) {
|
||||
var current = check(node);
|
||||
if (
|
||||
node.lang ||
|
||||
/^\s*([~`])\1{2,}/.test(contents.slice(initial, final))
|
||||
) {
|
||||
return 'fenced';
|
||||
}
|
||||
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!preferred) {
|
||||
preferred = current;
|
||||
} else if (preferred !== current) {
|
||||
file.warn('Code blocks should be ' + preferred, node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
return 'indented';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = codeBlockStyle;
|
||||
|
@ -15,19 +15,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Expressions.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = definitionCase;
|
||||
|
||||
/* Expressions. */
|
||||
var LABEL = /^\s*\[((?:\\[\s\S]|[^\[\]])+)\]/;
|
||||
|
||||
/**
|
||||
@ -36,42 +31,34 @@ var LABEL = /^\s*\[((?:\\[\s\S]|[^\[\]])+)\]/;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function definitionCase(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function definitionCase(ast, file) {
|
||||
var contents = file.toString();
|
||||
|
||||
/**
|
||||
* Validate a node, either a normal definition or
|
||||
* a footnote definition.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function validate(node) {
|
||||
var start = position.start(node).offset;
|
||||
var end = position.end(node).offset;
|
||||
var label;
|
||||
visit(ast, 'definition', validate);
|
||||
visit(ast, 'footnoteDefinition', validate);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
label = contents.slice(start, end).match(LABEL)[1];
|
||||
/**
|
||||
* Validate a node, either a normal definition or
|
||||
* a footnote definition.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function validate(node) {
|
||||
var start = position.start(node).offset;
|
||||
var end = position.end(node).offset;
|
||||
var label;
|
||||
|
||||
if (label !== label.toLowerCase()) {
|
||||
file.warn('Do not use upper-case characters in definition labels', node);
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'definition', validate);
|
||||
visit(ast, 'footnoteDefinition', validate);
|
||||
label = contents.slice(start, end).match(LABEL)[1];
|
||||
|
||||
done();
|
||||
if (label !== label.toLowerCase()) {
|
||||
file.warn('Do not use upper-case characters in definition labels', node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = definitionCase;
|
||||
|
@ -15,19 +15,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Expressions.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = definitionSpacing;
|
||||
|
||||
/* Expressions. */
|
||||
var LABEL = /^\s*\[((?:\\[\s\S]|[^\[\]])+)\]/;
|
||||
|
||||
/**
|
||||
@ -36,42 +31,34 @@ var LABEL = /^\s*\[((?:\\[\s\S]|[^\[\]])+)\]/;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function definitionSpacing(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function definitionSpacing(ast, file) {
|
||||
var contents = file.toString();
|
||||
|
||||
/**
|
||||
* Validate a node, either a normal definition or
|
||||
* a footnote definition.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function validate(node) {
|
||||
var start = position.start(node).offset;
|
||||
var end = position.end(node).offset;
|
||||
var label;
|
||||
visit(ast, 'definition', validate);
|
||||
visit(ast, 'footnoteDefinition', validate);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
label = contents.slice(start, end).match(LABEL)[1];
|
||||
/**
|
||||
* Validate a node, either a normal definition or
|
||||
* a footnote definition.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function validate(node) {
|
||||
var start = position.start(node).offset;
|
||||
var end = position.end(node).offset;
|
||||
var label;
|
||||
|
||||
if (/[ \t\n]{2,}/.test(label)) {
|
||||
file.warn('Do not use consecutive white-space in definition labels', node);
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'definition', validate);
|
||||
visit(ast, 'footnoteDefinition', validate);
|
||||
label = contents.slice(start, end).match(LABEL)[1];
|
||||
|
||||
done();
|
||||
if (/[ \t\n]{2,}/.test(label)) {
|
||||
file.warn('Do not use consecutive white-space in definition labels', node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = definitionSpacing;
|
||||
|
@ -26,21 +26,18 @@
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Map of valid markers.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = emphasisMarker;
|
||||
|
||||
/* Map of valid markers. */
|
||||
var MARKERS = {
|
||||
'*': true,
|
||||
'_': true,
|
||||
'null': true
|
||||
'*': true,
|
||||
'_': true,
|
||||
'null': true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -50,39 +47,28 @@ var MARKERS = {
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {string?} [preferred='consistent'] - Preferred
|
||||
* marker, either `'*'` or `'_'`, or `'consistent'`.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function emphasisMarker(ast, file, preferred, done) {
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
function emphasisMarker(ast, file, preferred) {
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
|
||||
if (MARKERS[preferred] !== true) {
|
||||
file.fail('Invalid emphasis marker `' + preferred + '`: use either `\'consistent\'`, `\'*\'`, or `\'_\'`');
|
||||
done();
|
||||
if (MARKERS[preferred] !== true) {
|
||||
file.fail('Invalid emphasis marker `' + preferred + '`: use either `\'consistent\'`, `\'*\'`, or `\'_\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
visit(ast, 'emphasis', function (node) {
|
||||
var marker = file.toString().charAt(position.start(node).offset);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'emphasis', function (node) {
|
||||
var marker = file.toString().charAt(position.start(node).offset);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (preferred) {
|
||||
if (marker !== preferred) {
|
||||
file.warn('Emphasis should use `' + preferred + '` as a marker', node);
|
||||
}
|
||||
} else {
|
||||
preferred = marker;
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (preferred) {
|
||||
if (marker !== preferred) {
|
||||
file.warn('Emphasis should use `' + preferred + '` as a marker', node);
|
||||
}
|
||||
} else {
|
||||
preferred = marker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = emphasisMarker;
|
||||
|
@ -42,19 +42,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = fencedCodeFlag;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
@ -65,44 +60,35 @@ var end = position.end;
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {Object|Array.<string>} [preferred] - List
|
||||
* of flags deemed valid.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function fencedCodeFlag(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
var allowEmpty = false;
|
||||
var flags = [];
|
||||
function fencedCodeFlag(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
var allowEmpty = false;
|
||||
var flags = [];
|
||||
|
||||
if (typeof preferred === 'object' && !('length' in preferred)) {
|
||||
allowEmpty = Boolean(preferred.allowEmpty);
|
||||
if (typeof preferred === 'object' && !('length' in preferred)) {
|
||||
allowEmpty = Boolean(preferred.allowEmpty);
|
||||
|
||||
preferred = preferred.flags;
|
||||
preferred = preferred.flags;
|
||||
}
|
||||
|
||||
if (typeof preferred === 'object' && 'length' in preferred) {
|
||||
flags = String(preferred).split(',');
|
||||
}
|
||||
|
||||
visit(ast, 'code', function (node) {
|
||||
var value = contents.slice(start(node).offset, end(node).offset);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof preferred === 'object' && 'length' in preferred) {
|
||||
flags = String(preferred).split(',');
|
||||
if (node.lang) {
|
||||
if (flags.length && flags.indexOf(node.lang) === -1) {
|
||||
file.warn('Invalid code-language flag', node);
|
||||
}
|
||||
} else if (/^ {0,3}([~`])\1{2,}/.test(value) && !allowEmpty) {
|
||||
file.warn('Missing code-language flag', node);
|
||||
}
|
||||
|
||||
visit(ast, 'code', function (node) {
|
||||
var value = contents.slice(start(node).offset, end(node).offset);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.lang) {
|
||||
if (flags.length && flags.indexOf(node.lang) === -1) {
|
||||
file.warn('Invalid code-language flag', node);
|
||||
}
|
||||
} else if (/^\ {0,3}([~`])\1{2,}/.test(value) && !allowEmpty) {
|
||||
file.warn('Missing code-language flag', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = fencedCodeFlag;
|
||||
|
@ -42,23 +42,18 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Map of valid markers.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = fencedCodeMarker;
|
||||
|
||||
/* Map of valid markers. */
|
||||
var MARKERS = {
|
||||
'`': true,
|
||||
'~': true,
|
||||
'null': true
|
||||
'`': true,
|
||||
'~': true,
|
||||
'null': true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -68,51 +63,37 @@ var MARKERS = {
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {string?} [preferred='consistent'] - Preferred
|
||||
* marker, either `` '`' `` or `~`, or `'consistent'`.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function fencedCodeMarker(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function fencedCodeMarker(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
|
||||
if (MARKERS[preferred] !== true) {
|
||||
file.fail('Invalid fenced code marker `' + preferred + '`: use either `\'consistent\'`, `` \'\`\' ``, or `\'~\'`');
|
||||
done();
|
||||
if (MARKERS[preferred] !== true) {
|
||||
file.fail('Invalid fenced code marker `' + preferred + '`: use either `\'consistent\'`, `` \'`\' ``, or `\'~\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
visit(ast, 'code', function (node) {
|
||||
var marker = contents.substr(position.start(node).offset, 4);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'code', function (node) {
|
||||
var marker = contents.substr(position.start(node).offset, 4);
|
||||
marker = marker.trimLeft().charAt(0);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
/* Ignore unfenced code blocks. */
|
||||
if (MARKERS[marker] !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
marker = marker.trimLeft().charAt(0);
|
||||
|
||||
/*
|
||||
* Ignore unfenced code blocks.
|
||||
*/
|
||||
|
||||
if (MARKERS[marker] !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (preferred) {
|
||||
if (marker !== preferred) {
|
||||
file.warn('Fenced code should use ' + preferred + ' as a marker', node);
|
||||
}
|
||||
} else {
|
||||
preferred = marker;
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (preferred) {
|
||||
if (marker !== preferred) {
|
||||
file.warn('Fenced code should use ' + preferred + ' as a marker', node);
|
||||
}
|
||||
} else {
|
||||
preferred = marker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = fencedCodeMarker;
|
||||
|
@ -18,7 +18,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
/* Expose. */
|
||||
module.exports = fileExtension;
|
||||
|
||||
/**
|
||||
* Check file extensions.
|
||||
@ -27,22 +28,13 @@
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {string?} [preferred='md'] - Expected file
|
||||
* extension.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function fileExtension(ast, file, preferred, done) {
|
||||
var ext = file.extension;
|
||||
function fileExtension(ast, file, preferred) {
|
||||
var ext = file.extension;
|
||||
|
||||
preferred = typeof preferred === 'string' ? preferred : 'md';
|
||||
preferred = typeof preferred === 'string' ? preferred : 'md';
|
||||
|
||||
if (ext !== '' && ext !== preferred) {
|
||||
file.warn('Invalid extension: use `' + preferred + '`');
|
||||
}
|
||||
|
||||
done();
|
||||
if (ext !== '' && ext !== preferred) {
|
||||
file.warn('Invalid extension: use `' + preferred + '`');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = fileExtension;
|
||||
|
@ -21,19 +21,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = finalDefinition;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
|
||||
/**
|
||||
@ -42,37 +37,24 @@ var start = position.start;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function finalDefinition(ast, file, preferred, done) {
|
||||
var last = null;
|
||||
function finalDefinition(ast, file) {
|
||||
var last = null;
|
||||
|
||||
visit(ast, function (node) {
|
||||
var line = start(node).line;
|
||||
visit(ast, function (node) {
|
||||
var line = start(node).line;
|
||||
|
||||
/*
|
||||
* Ignore generated nodes.
|
||||
*/
|
||||
/* Ignore generated nodes. */
|
||||
if (node.type === 'root' || position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.type === 'root' || position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.type === 'definition') {
|
||||
if (last !== null && last > line) {
|
||||
file.warn('Move definitions to the end of the file (after the node at line `' + last + '`)', node);
|
||||
}
|
||||
} else if (last === null) {
|
||||
last = line;
|
||||
}
|
||||
}, true);
|
||||
|
||||
done();
|
||||
if (node.type === 'definition') {
|
||||
if (last !== null && last > line) {
|
||||
file.warn('Move definitions to the end of the file (after the node at line `' + last + '`)', node);
|
||||
}
|
||||
} else if (last === null) {
|
||||
last = line;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = finalDefinition;
|
||||
|
@ -12,7 +12,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
/* Expose. */
|
||||
module.exports = finalNewline;
|
||||
|
||||
/**
|
||||
* Warn when the list-item marker style of unordered lists
|
||||
@ -20,22 +21,12 @@
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function finalNewline(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
var last = contents.length - 1;
|
||||
function finalNewline(ast, file) {
|
||||
var contents = file.toString();
|
||||
var last = contents.length - 1;
|
||||
|
||||
if (last > 0 && contents.charAt(last) !== '\n') {
|
||||
file.warn('Missing newline character at end of file');
|
||||
}
|
||||
|
||||
done();
|
||||
if (last > 0 && contents.charAt(last) !== '\n') {
|
||||
file.warn('Missing newline character at end of file');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = finalNewline;
|
||||
|
@ -21,39 +21,32 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = firstHeadingLevel;
|
||||
|
||||
/**
|
||||
* Warn when the first heading has a level other than a specified value.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {number?} [preferred=1] - First heading level.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function firstHeadingLevel(ast, file, preferred, done) {
|
||||
var style = preferred && preferred !== true ? preferred : 1;
|
||||
function firstHeadingLevel(ast, file, preferred) {
|
||||
var style = preferred && preferred !== true ? preferred : 1;
|
||||
|
||||
visit(ast, 'heading', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return null;
|
||||
}
|
||||
visit(ast, 'heading', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.depth !== style) {
|
||||
file.warn('First heading level should be `' + style + '`', node);
|
||||
}
|
||||
if (node.depth !== style) {
|
||||
file.warn('First heading level should be `' + style + '`', node);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
done();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = firstHeadingLevel;
|
||||
|
@ -21,46 +21,36 @@
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = hardBreakSpaces;
|
||||
|
||||
/**
|
||||
* Warn when too many spaces are used to create a
|
||||
* hard break.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function hardBreakSpaces(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function hardBreakSpaces(ast, file) {
|
||||
var contents = file.toString();
|
||||
|
||||
visit(ast, 'break', function (node) {
|
||||
var start = position.start(node).offset;
|
||||
var end = position.end(node).offset;
|
||||
var value;
|
||||
visit(ast, 'break', function (node) {
|
||||
var start = position.start(node).offset;
|
||||
var end = position.end(node).offset;
|
||||
var value;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
value = contents.slice(start, end).split('\n', 1)[0].replace(/\r$/, '');
|
||||
value = contents.slice(start, end).split('\n', 1)[0].replace(/\r$/, '');
|
||||
|
||||
if (value.length > 2) {
|
||||
file.warn('Use two spaces for hard line breaks', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (value.length > 2) {
|
||||
file.warn('Use two spaces for hard line breaks', node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = hardBreakSpaces;
|
||||
|
@ -19,15 +19,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = headingIncrement;
|
||||
|
||||
/**
|
||||
* Warn when headings increment with more than 1 level at
|
||||
* a time.
|
||||
@ -36,31 +34,21 @@ var position = require('unist-util-position');
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function headingIncrement(ast, file, preferred, done) {
|
||||
var prev = null;
|
||||
function headingIncrement(ast, file) {
|
||||
var prev = null;
|
||||
|
||||
visit(ast, 'heading', function (node) {
|
||||
var depth = node.depth;
|
||||
visit(ast, 'heading', function (node) {
|
||||
var depth = node.depth;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prev && depth > prev + 1) {
|
||||
file.warn('Heading levels should increment by one level at a time', node);
|
||||
}
|
||||
if (prev && depth > prev + 1) {
|
||||
file.warn('Heading levels should increment by one level at a time', node);
|
||||
}
|
||||
|
||||
prev = depth;
|
||||
});
|
||||
|
||||
done();
|
||||
prev = depth;
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = headingIncrement;
|
||||
|
@ -49,18 +49,15 @@
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var style = require('mdast-util-heading-style');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Types.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = headingStyle;
|
||||
|
||||
/* Types. */
|
||||
var TYPES = ['atx', 'atx-closed', 'setext'];
|
||||
|
||||
/**
|
||||
@ -74,28 +71,20 @@ var TYPES = ['atx', 'atx-closed', 'setext'];
|
||||
* detect the first used style.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function headingStyle(ast, file, preferred, done) {
|
||||
preferred = TYPES.indexOf(preferred) === -1 ? null : preferred;
|
||||
function headingStyle(ast, file, preferred) {
|
||||
preferred = TYPES.indexOf(preferred) === -1 ? null : preferred;
|
||||
|
||||
visit(ast, 'heading', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
visit(ast, 'heading', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (preferred) {
|
||||
if (style(node, preferred) !== preferred) {
|
||||
file.warn('Headings should use ' + preferred, node);
|
||||
}
|
||||
} else {
|
||||
preferred = style(node, preferred);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (preferred) {
|
||||
if (style(node, preferred) !== preferred) {
|
||||
file.warn('Headings should use ' + preferred, node);
|
||||
}
|
||||
} else {
|
||||
preferred = style(node, preferred);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = headingStyle;
|
||||
|
@ -8,68 +8,63 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
/* Expose. */
|
||||
module.exports = {
|
||||
'no-auto-link-without-protocol': require('./no-auto-link-without-protocol'),
|
||||
'no-literal-urls': require('./no-literal-urls'),
|
||||
'no-consecutive-blank-lines': require('./no-consecutive-blank-lines'),
|
||||
'no-missing-blank-lines': require('./no-missing-blank-lines'),
|
||||
'blockquote-indentation': require('./blockquote-indentation'),
|
||||
'no-blockquote-without-caret': require('./no-blockquote-without-caret'),
|
||||
'code-block-style': require('./code-block-style'),
|
||||
'checkbox-content-indent': require('./checkbox-content-indent'),
|
||||
'checkbox-character-style': require('./checkbox-character-style'),
|
||||
'definition-case': require('./definition-case'),
|
||||
'definition-spacing': require('./definition-spacing'),
|
||||
'no-emphasis-as-heading': require('./no-emphasis-as-heading'),
|
||||
'emphasis-marker': require('./emphasis-marker'),
|
||||
'fenced-code-flag': require('./fenced-code-flag'),
|
||||
'fenced-code-marker': require('./fenced-code-marker'),
|
||||
'file-extension': require('./file-extension'),
|
||||
'final-newline': require('./final-newline'),
|
||||
'no-file-name-articles': require('./no-file-name-articles'),
|
||||
'no-file-name-consecutive-dashes': require('./no-file-name-consecutive-dashes'),
|
||||
'no-file-name-irregular-characters': require('./no-file-name-irregular-characters'),
|
||||
'no-file-name-mixed-case': require('./no-file-name-mixed-case'),
|
||||
'no-file-name-outer-dashes': require('./no-file-name-outer-dashes'),
|
||||
'final-definition': require('./final-definition'),
|
||||
'hard-break-spaces': require('./hard-break-spaces'),
|
||||
'heading-increment': require('./heading-increment'),
|
||||
'no-heading-content-indent': require('./no-heading-content-indent'),
|
||||
'no-heading-indent': require('./no-heading-indent'),
|
||||
'first-heading-level': require('./first-heading-level'),
|
||||
'maximum-heading-length': require('./maximum-heading-length'),
|
||||
'no-heading-punctuation': require('./no-heading-punctuation'),
|
||||
'heading-style': require('./heading-style'),
|
||||
'no-multiple-toplevel-headings': require('./no-multiple-toplevel-headings'),
|
||||
'no-duplicate-headings': require('./no-duplicate-headings'),
|
||||
'no-duplicate-definitions': require('./no-duplicate-definitions'),
|
||||
'no-html': require('./no-html'),
|
||||
'no-inline-padding': require('./no-inline-padding'),
|
||||
'maximum-line-length': require('./maximum-line-length'),
|
||||
'link-title-style': require('./link-title-style'),
|
||||
'list-item-bullet-indent': require('./list-item-bullet-indent'),
|
||||
'list-item-content-indent': require('./list-item-content-indent'),
|
||||
'list-item-indent': require('./list-item-indent'),
|
||||
'list-item-spacing': require('./list-item-spacing'),
|
||||
'ordered-list-marker-style': require('./ordered-list-marker-style'),
|
||||
'ordered-list-marker-value': require('./ordered-list-marker-value'),
|
||||
'no-shortcut-reference-image': require('./no-shortcut-reference-image'),
|
||||
'no-shortcut-reference-link': require('./no-shortcut-reference-link'),
|
||||
'rule-style': require('./rule-style'),
|
||||
'no-shell-dollars': require('./no-shell-dollars'),
|
||||
'strong-marker': require('./strong-marker'),
|
||||
'no-table-indentation': require('./no-table-indentation'),
|
||||
'table-pipe-alignment': require('./table-pipe-alignment'),
|
||||
'table-cell-padding': require('./table-cell-padding'),
|
||||
'table-pipes': require('./table-pipes'),
|
||||
'no-tabs': require('./no-tabs'),
|
||||
'unordered-list-marker-style': require('./unordered-list-marker-style'),
|
||||
'no-undefined-references': require('./no-undefined-references.js'),
|
||||
'no-unused-definitions': require('./no-unused-definitions.js')
|
||||
'no-auto-link-without-protocol': require('./no-auto-link-without-protocol'),
|
||||
'no-literal-urls': require('./no-literal-urls'),
|
||||
'no-consecutive-blank-lines': require('./no-consecutive-blank-lines'),
|
||||
'no-missing-blank-lines': require('./no-missing-blank-lines'),
|
||||
'blockquote-indentation': require('./blockquote-indentation'),
|
||||
'no-blockquote-without-caret': require('./no-blockquote-without-caret'),
|
||||
'code-block-style': require('./code-block-style'),
|
||||
'checkbox-content-indent': require('./checkbox-content-indent'),
|
||||
'checkbox-character-style': require('./checkbox-character-style'),
|
||||
'definition-case': require('./definition-case'),
|
||||
'definition-spacing': require('./definition-spacing'),
|
||||
'no-emphasis-as-heading': require('./no-emphasis-as-heading'),
|
||||
'emphasis-marker': require('./emphasis-marker'),
|
||||
'fenced-code-flag': require('./fenced-code-flag'),
|
||||
'fenced-code-marker': require('./fenced-code-marker'),
|
||||
'file-extension': require('./file-extension'),
|
||||
'final-newline': require('./final-newline'),
|
||||
'no-file-name-articles': require('./no-file-name-articles'),
|
||||
'no-file-name-consecutive-dashes': require('./no-file-name-consecutive-dashes'),
|
||||
'no-file-name-irregular-characters': require('./no-file-name-irregular-characters'),
|
||||
'no-file-name-mixed-case': require('./no-file-name-mixed-case'),
|
||||
'no-file-name-outer-dashes': require('./no-file-name-outer-dashes'),
|
||||
'final-definition': require('./final-definition'),
|
||||
'hard-break-spaces': require('./hard-break-spaces'),
|
||||
'heading-increment': require('./heading-increment'),
|
||||
'no-heading-content-indent': require('./no-heading-content-indent'),
|
||||
'no-heading-indent': require('./no-heading-indent'),
|
||||
'first-heading-level': require('./first-heading-level'),
|
||||
'maximum-heading-length': require('./maximum-heading-length'),
|
||||
'no-heading-punctuation': require('./no-heading-punctuation'),
|
||||
'heading-style': require('./heading-style'),
|
||||
'no-multiple-toplevel-headings': require('./no-multiple-toplevel-headings'),
|
||||
'no-duplicate-headings': require('./no-duplicate-headings'),
|
||||
'no-duplicate-definitions': require('./no-duplicate-definitions'),
|
||||
'no-html': require('./no-html'),
|
||||
'no-inline-padding': require('./no-inline-padding'),
|
||||
'maximum-line-length': require('./maximum-line-length'),
|
||||
'link-title-style': require('./link-title-style'),
|
||||
'list-item-bullet-indent': require('./list-item-bullet-indent'),
|
||||
'list-item-content-indent': require('./list-item-content-indent'),
|
||||
'list-item-indent': require('./list-item-indent'),
|
||||
'list-item-spacing': require('./list-item-spacing'),
|
||||
'ordered-list-marker-style': require('./ordered-list-marker-style'),
|
||||
'ordered-list-marker-value': require('./ordered-list-marker-value'),
|
||||
'no-shortcut-reference-image': require('./no-shortcut-reference-image'),
|
||||
'no-shortcut-reference-link': require('./no-shortcut-reference-link'),
|
||||
'rule-style': require('./rule-style'),
|
||||
'no-shell-dollars': require('./no-shell-dollars'),
|
||||
'strong-marker': require('./strong-marker'),
|
||||
'no-table-indentation': require('./no-table-indentation'),
|
||||
'table-pipe-alignment': require('./table-pipe-alignment'),
|
||||
'table-cell-padding': require('./table-cell-padding'),
|
||||
'table-pipes': require('./table-pipes'),
|
||||
'no-tabs': require('./no-tabs'),
|
||||
'unordered-list-marker-style': require('./unordered-list-marker-style'),
|
||||
'no-undefined-references': require('./no-undefined-references.js'),
|
||||
'no-unused-definitions': require('./no-unused-definitions.js')
|
||||
};
|
||||
|
@ -33,33 +33,25 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var vfileLocation = require('vfile-location');
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Map of valid markers.
|
||||
*/
|
||||
|
||||
var MARKERS = {
|
||||
'"': true,
|
||||
'\'': true,
|
||||
')': true,
|
||||
'null': true
|
||||
};
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = linkTitleStyle;
|
||||
|
||||
/* Methods. */
|
||||
var end = position.end;
|
||||
|
||||
/* Map of valid markers. */
|
||||
var MARKERS = {
|
||||
'"': true,
|
||||
'\'': true,
|
||||
')': true,
|
||||
'null': true
|
||||
};
|
||||
|
||||
/**
|
||||
* Warn for fenced code blocks without language flag.
|
||||
*
|
||||
@ -67,78 +59,66 @@ var end = position.end;
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {string?} [preferred='consistent'] - Preferred
|
||||
* marker, either `'"'`, `'\''`, `'()'`, or `'consistent'`.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function linkTitleStyle(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
function linkTitleStyle(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
|
||||
if (preferred === '()' || preferred === '(') {
|
||||
preferred = ')';
|
||||
if (preferred === '()' || preferred === '(') {
|
||||
preferred = ')';
|
||||
}
|
||||
|
||||
if (MARKERS[preferred] !== true) {
|
||||
file.fail('Invalid link title style marker `' + preferred + '`: use either `\'consistent\'`, `\'"\'`, `\'\\\'\'`, or `\'()\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'link', validate);
|
||||
visit(ast, 'image', validate);
|
||||
visit(ast, 'definition', validate);
|
||||
|
||||
return;
|
||||
|
||||
/**
|
||||
* Validate a single node.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function validate(node) {
|
||||
var last = end(node).offset - 1;
|
||||
var character;
|
||||
var pos;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MARKERS[preferred] !== true) {
|
||||
file.fail('Invalid link title style marker `' + preferred + '`: use either `\'consistent\'`, `\'"\'`, `\'\\\'\'`, or `\'()\'`');
|
||||
done();
|
||||
|
||||
return;
|
||||
if (node.type !== 'definition') {
|
||||
last--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a single node.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function validate(node) {
|
||||
var last = end(node).offset - 1;
|
||||
var character;
|
||||
var pos;
|
||||
while (last) {
|
||||
character = contents.charAt(last);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.type !== 'definition') {
|
||||
last--;
|
||||
}
|
||||
|
||||
while (last) {
|
||||
character = contents.charAt(last);
|
||||
|
||||
if (/\s/.test(character)) {
|
||||
last--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Not a title.
|
||||
*/
|
||||
|
||||
if (!(character in MARKERS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!preferred) {
|
||||
preferred = character;
|
||||
} else if (preferred !== character) {
|
||||
pos = location.toPosition(last + 1);
|
||||
file.warn('Titles should use `' + (preferred === ')' ? '()' : preferred) + '` as a quote', pos);
|
||||
}
|
||||
if (/\s/.test(character)) {
|
||||
last--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
visit(ast, 'link', validate);
|
||||
visit(ast, 'image', validate);
|
||||
visit(ast, 'definition', validate);
|
||||
/* Not a title. */
|
||||
if (!(character in MARKERS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
done();
|
||||
if (!preferred) {
|
||||
preferred = character;
|
||||
} else if (preferred !== character) {
|
||||
pos = location.toPosition(last + 1);
|
||||
file.warn('Titles should use `' + (preferred === ')' ? '()' : preferred) + '` as a quote', pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = linkTitleStyle;
|
||||
|
@ -17,20 +17,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
var plural = require('plur');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = listItemBulletIndent;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
|
||||
/**
|
||||
@ -38,43 +33,33 @@ var start = position.start;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function listItemBulletIndent(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function listItemBulletIndent(ast, file) {
|
||||
var contents = file.toString();
|
||||
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
|
||||
items.forEach(function (item) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var indent;
|
||||
items.forEach(function (item) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var indent;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
indent = contents.slice(initial, final).match(/^\s*/)[0].length;
|
||||
indent = contents.slice(initial, final).match(/^\s*/)[0].length;
|
||||
|
||||
if (indent !== 0) {
|
||||
initial = start(head);
|
||||
if (indent !== 0) {
|
||||
initial = start(head);
|
||||
|
||||
file.warn('Incorrect indentation before bullet: remove ' + indent + ' ' + plural('space', indent), {
|
||||
'line': initial.line,
|
||||
'column': initial.column - indent
|
||||
});
|
||||
}
|
||||
file.warn('Incorrect indentation before bullet: remove ' + indent + ' ' + plural('space', indent), {
|
||||
line: initial.line,
|
||||
column: initial.column - indent
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = listItemBulletIndent;
|
||||
|
@ -19,20 +19,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
var plural = require('plur');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = listItemContentIndent;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
|
||||
/**
|
||||
@ -41,81 +36,62 @@ var start = position.start;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function listItemContentIndent(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function listItemContentIndent(ast, file) {
|
||||
var contents = file.toString();
|
||||
|
||||
visit(ast, 'listItem', function (node) {
|
||||
var style;
|
||||
visit(ast, 'listItem', function (node) {
|
||||
var style;
|
||||
|
||||
node.children.forEach(function (item, index) {
|
||||
var begin = start(item);
|
||||
var column = begin.column;
|
||||
var char;
|
||||
var diff;
|
||||
var word;
|
||||
node.children.forEach(function (item, index) {
|
||||
var begin = start(item);
|
||||
var column = begin.column;
|
||||
var char;
|
||||
var diff;
|
||||
var word;
|
||||
|
||||
if (position.generated(item)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get indentation for the first child.
|
||||
* Only the first item can have a checkbox,
|
||||
* so here we remove that from the column.
|
||||
*/
|
||||
/* Get indentation for the first child.
|
||||
* Only the first item can have a checkbox,
|
||||
* so here we remove that from the column. */
|
||||
if (index === 0) {
|
||||
/* If there’s a checkbox before the content,
|
||||
* look backwards to find the start of that
|
||||
* checkbox. */
|
||||
if (Boolean(node.checked) === node.checked) {
|
||||
char = begin.offset - 1;
|
||||
|
||||
if (index === 0) {
|
||||
/*
|
||||
* If there’s a checkbox before the content,
|
||||
* look backwards to find the start of that
|
||||
* checkbox.
|
||||
*/
|
||||
while (contents.charAt(char) !== '[') {
|
||||
char--;
|
||||
}
|
||||
|
||||
if (Boolean(node.checked) === node.checked) {
|
||||
char = begin.offset - 1;
|
||||
column -= begin.offset - char;
|
||||
}
|
||||
|
||||
while (contents.charAt(char) !== '[') {
|
||||
char--;
|
||||
}
|
||||
style = column;
|
||||
|
||||
column -= begin.offset - char;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
style = column;
|
||||
/* Warn for violating children. */
|
||||
if (column !== style) {
|
||||
diff = style - column;
|
||||
word = diff > 0 ? 'add' : 'remove';
|
||||
|
||||
return;
|
||||
}
|
||||
diff = Math.abs(diff);
|
||||
|
||||
/*
|
||||
* Warn for violating children.
|
||||
*/
|
||||
|
||||
if (column !== style) {
|
||||
diff = style - column;
|
||||
word = diff > 0 ? 'add' : 'remove';
|
||||
|
||||
diff = Math.abs(diff);
|
||||
|
||||
file.warn(
|
||||
'Don’t use mixed indentation for children, ' + word +
|
||||
' ' + diff + ' ' + plural('space', diff),
|
||||
{
|
||||
'line': start(item).line,
|
||||
'column': column
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
file.warn(
|
||||
'Don’t use mixed indentation for children, ' + word +
|
||||
' ' + diff + ' ' + plural('space', diff),
|
||||
{
|
||||
line: start(item).line,
|
||||
column: column
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = listItemContentIndent;
|
||||
|
@ -44,28 +44,22 @@
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
var plural = require('plur');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = listItemIndent;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
|
||||
/*
|
||||
* Styles.
|
||||
*/
|
||||
|
||||
/* Styles. */
|
||||
var STYLES = {
|
||||
'tab-size': true,
|
||||
'mixed': true,
|
||||
'space': true
|
||||
'tab-size': true,
|
||||
'mixed': true,
|
||||
'space': true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -79,75 +73,62 @@ var STYLES = {
|
||||
* to the first.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function listItemIndent(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function listItemIndent(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
|
||||
preferred = typeof preferred !== 'string' ? 'tab-size' : preferred;
|
||||
preferred = typeof preferred === 'string' ? preferred : 'tab-size';
|
||||
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid list-item indent style `' + preferred + '`: use either `\'tab-size\'`, `\'space\'`, or `\'mixed\'`');
|
||||
done();
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid list-item indent style `' + preferred + '`: use either `\'tab-size\'`, `\'space\'`, or `\'mixed\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
items.forEach(function (item) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var bulletSize;
|
||||
var tab;
|
||||
var marker;
|
||||
var shouldBe;
|
||||
var diff;
|
||||
var word;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
marker = contents.slice(initial, final);
|
||||
|
||||
items.forEach(function (item) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var bulletSize;
|
||||
var tab;
|
||||
var marker;
|
||||
var shouldBe;
|
||||
var diff;
|
||||
var word;
|
||||
/* Support checkboxes. */
|
||||
marker = marker.replace(/\[[x ]?\]\s*$/i, '');
|
||||
|
||||
marker = contents.slice(initial, final);
|
||||
bulletSize = marker.trimRight().length;
|
||||
tab = Math.ceil(bulletSize / 4) * 4;
|
||||
|
||||
/*
|
||||
* Support checkboxes.
|
||||
*/
|
||||
if (preferred === 'tab-size') {
|
||||
shouldBe = tab;
|
||||
} else if (preferred === 'space') {
|
||||
shouldBe = bulletSize + 1;
|
||||
} else {
|
||||
shouldBe = node.loose ? tab : bulletSize + 1;
|
||||
}
|
||||
|
||||
marker = marker.replace(/\[[x ]?\]\s*$/i, '');
|
||||
if (marker.length !== shouldBe) {
|
||||
diff = shouldBe - marker.length;
|
||||
word = diff > 0 ? 'add' : 'remove';
|
||||
|
||||
bulletSize = marker.trimRight().length;
|
||||
tab = Math.ceil(bulletSize / 4) * 4;
|
||||
diff = Math.abs(diff);
|
||||
|
||||
if (preferred === 'tab-size') {
|
||||
shouldBe = tab;
|
||||
} else if (preferred === 'space') {
|
||||
shouldBe = bulletSize + 1;
|
||||
} else {
|
||||
shouldBe = node.loose ? tab : bulletSize + 1;
|
||||
}
|
||||
|
||||
if (marker.length !== shouldBe) {
|
||||
diff = shouldBe - marker.length;
|
||||
word = diff > 0 ? 'add' : 'remove';
|
||||
|
||||
diff = Math.abs(diff);
|
||||
|
||||
file.warn(
|
||||
'Incorrect list-item indent: ' + word +
|
||||
' ' + diff + ' ' + plural('space', diff),
|
||||
start(head)
|
||||
);
|
||||
}
|
||||
});
|
||||
file.warn(
|
||||
'Incorrect list-item indent: ' + word +
|
||||
' ' + diff + ' ' + plural('space', diff),
|
||||
start(head)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = listItemIndent;
|
||||
|
@ -36,19 +36,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = listItemSpacing;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
@ -58,71 +53,55 @@ var end = position.end;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function listItemSpacing(ast, file, preferred, done) {
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
var isTightList = true;
|
||||
var indent = start(node).column;
|
||||
var type;
|
||||
function listItemSpacing(ast, file) {
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
var isTightList = true;
|
||||
var indent = start(node).column;
|
||||
var type;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
items.forEach(function (item) {
|
||||
var content = item.children;
|
||||
var head = content[0];
|
||||
var tail = content[content.length - 1];
|
||||
var isLoose = (end(tail).line - start(head).line) > 0;
|
||||
items.forEach(function (item) {
|
||||
var content = item.children;
|
||||
var head = content[0];
|
||||
var tail = content[content.length - 1];
|
||||
var isLoose = (end(tail).line - start(head).line) > 0;
|
||||
|
||||
if (isLoose) {
|
||||
isTightList = false;
|
||||
}
|
||||
});
|
||||
|
||||
type = isTightList ? 'tight' : 'loose';
|
||||
|
||||
items.forEach(function (item, index) {
|
||||
var next = items[index + 1];
|
||||
var isTight = end(item).column > indent;
|
||||
|
||||
/*
|
||||
* Ignore last.
|
||||
*/
|
||||
|
||||
if (!next) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the list item's state does (not)
|
||||
* match the list's state.
|
||||
*/
|
||||
|
||||
if (isTight !== isTightList) {
|
||||
if (type === 'loose') {
|
||||
file.warn('Missing new line after list item', {
|
||||
'start': end(item),
|
||||
'end': start(next)
|
||||
});
|
||||
} else {
|
||||
file.warn('Extraneous new line after list item', {
|
||||
'start': end(item),
|
||||
'end': start(next)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
if (isLoose) {
|
||||
isTightList = false;
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
type = isTightList ? 'tight' : 'loose';
|
||||
|
||||
items.forEach(function (item, index) {
|
||||
var next = items[index + 1];
|
||||
var isTight = end(item).column > indent;
|
||||
|
||||
/* Ignore last. */
|
||||
if (!next) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the list item's state does (not)
|
||||
* match the list's state. */
|
||||
if (isTight !== isTightList) {
|
||||
if (type === 'loose') {
|
||||
file.warn('Missing new line after list item', {
|
||||
start: end(item),
|
||||
end: start(next)
|
||||
});
|
||||
} else {
|
||||
file.warn('Extraneous new line after list item', {
|
||||
start: end(item),
|
||||
end: start(next)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = listItemSpacing;
|
||||
|
@ -20,16 +20,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var toString = require('mdast-util-to-string');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = maximumHeadingLength;
|
||||
|
||||
/**
|
||||
* Warn when headings are too long.
|
||||
*
|
||||
@ -39,24 +37,16 @@ var position = require('unist-util-position');
|
||||
* length.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function maximumHeadingLength(ast, file, preferred, done) {
|
||||
preferred = isNaN(preferred) || typeof preferred !== 'number' ? 60 : preferred;
|
||||
function maximumHeadingLength(ast, file, preferred) {
|
||||
preferred = isNaN(preferred) || typeof preferred !== 'number' ? 60 : preferred;
|
||||
|
||||
visit(ast, 'heading', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
visit(ast, 'heading', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (toString(node).length > preferred) {
|
||||
file.warn('Use headings shorter than `' + preferred + '`', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (toString(node).length > preferred) {
|
||||
file.warn('Use headings shorter than `' + preferred + '`', node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = maximumHeadingLength;
|
||||
|
@ -32,22 +32,119 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = maximumLineLength;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
/**
|
||||
* Warn when lines are too long. This rule is forgiving
|
||||
* about lines which cannot be wrapped, such as code,
|
||||
* tables, and headings, or links at the enc of a line.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {number?} [preferred=80] - Maximum line length.
|
||||
*/
|
||||
function maximumLineLength(ast, file, preferred) {
|
||||
var style = preferred && preferred !== true ? preferred : 80;
|
||||
var content = file.toString();
|
||||
var matrix = content.split('\n');
|
||||
var index = -1;
|
||||
var length = matrix.length;
|
||||
var lineLength;
|
||||
|
||||
/* Next, white list nodes which cannot be wrapped. */
|
||||
visit(ast, function (node) {
|
||||
var applicable = isIgnored(node);
|
||||
var initial = applicable && start(node).line;
|
||||
var final = applicable && end(node).line;
|
||||
|
||||
if (!applicable || position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
whitelist(initial - 1, final);
|
||||
});
|
||||
|
||||
visit(ast, 'link', validateLink);
|
||||
visit(ast, 'image', validateLink);
|
||||
|
||||
/* Iterate over every line, and warn for
|
||||
* violating lines. */
|
||||
while (++index < length) {
|
||||
lineLength = matrix[index].length;
|
||||
|
||||
if (lineLength > style) {
|
||||
file.warn('Line must be at most ' + style + ' characters', {
|
||||
line: index + 1,
|
||||
column: lineLength + 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
/**
|
||||
* Whitelist from `initial` to `final`, zero-based.
|
||||
*
|
||||
* @param {number} initial - Start.
|
||||
* @param {number} final - End.
|
||||
*/
|
||||
function whitelist(initial, final) {
|
||||
initial--;
|
||||
|
||||
while (++initial < final) {
|
||||
matrix[initial] = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finally, whitelist URLs, but only if they occur at
|
||||
* or after the wrap. However, when they do, and
|
||||
* there’s white-space after it, they are not
|
||||
* whitelisted.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
* @param {number} pos - Position of `node` in `parent`.
|
||||
* @param {Node} parent - Parent of `node`.
|
||||
*/
|
||||
function validateLink(node, pos, parent) {
|
||||
var next = parent.children[pos + 1];
|
||||
var initial = start(node);
|
||||
var final = end(node);
|
||||
|
||||
/* Nothing to whitelist when generated. */
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* No whitelisting when starting after the border,
|
||||
* or ending before it. */
|
||||
if (initial.column > style || final.column < style) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* No whitelisting when there’s white-space after
|
||||
* the link. */
|
||||
if (
|
||||
next &&
|
||||
start(next).line === initial.line &&
|
||||
(!next.value || /^(.+?[ \t].+?)/.test(next.value))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
whitelist(initial.line - 1, final.line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if `node` is applicable, as in, if it should be
|
||||
* ignored.
|
||||
@ -57,132 +154,8 @@ var end = position.end;
|
||||
* ignored.
|
||||
*/
|
||||
function isIgnored(node) {
|
||||
return node.type === 'heading' ||
|
||||
node.type === 'table' ||
|
||||
node.type === 'code' ||
|
||||
node.type === 'definition';
|
||||
return node.type === 'heading' ||
|
||||
node.type === 'table' ||
|
||||
node.type === 'code' ||
|
||||
node.type === 'definition';
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn when lines are too long. This rule is forgiving
|
||||
* about lines which cannot be wrapped, such as code,
|
||||
* tables, and headings, or links at the enc of a line.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {number?} [preferred=80] - Maximum line length.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function maximumLineLength(ast, file, preferred, done) {
|
||||
var style = preferred && preferred !== true ? preferred : 80;
|
||||
var content = file.toString();
|
||||
var matrix = content.split('\n');
|
||||
var index = -1;
|
||||
var length = matrix.length;
|
||||
var lineLength;
|
||||
|
||||
/**
|
||||
* Whitelist from `initial` to `final`, zero-based.
|
||||
*
|
||||
* @param {number} initial - Start.
|
||||
* @param {number} final - End.
|
||||
*/
|
||||
function whitelist(initial, final) {
|
||||
initial--;
|
||||
|
||||
while (++initial < final) {
|
||||
matrix[initial] = '';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Next, white list nodes which cannot be wrapped.
|
||||
*/
|
||||
|
||||
visit(ast, function (node) {
|
||||
var applicable = isIgnored(node);
|
||||
var initial = applicable && start(node).line;
|
||||
var final = applicable && end(node).line;
|
||||
|
||||
if (!applicable || position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
whitelist(initial - 1, final);
|
||||
});
|
||||
|
||||
/**
|
||||
* Finally, whitelist URLs, but only if they occur at
|
||||
* or after the wrap. However, when they do, and
|
||||
* there’s white-space after it, they are not
|
||||
* whitelisted.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
* @param {number} pos - Position of `node` in `parent`.
|
||||
* @param {Node} parent - Parent of `node`.
|
||||
*/
|
||||
function validateLink(node, pos, parent) {
|
||||
var next = parent.children[pos + 1];
|
||||
var initial = start(node);
|
||||
var final = end(node);
|
||||
|
||||
/*
|
||||
* Nothing to whitelist when generated.
|
||||
*/
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* No whitelisting when starting after the border,
|
||||
* or ending before it.
|
||||
*/
|
||||
|
||||
if (initial.column > style || final.column < style) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* No whitelisting when there’s white-space after
|
||||
* the link.
|
||||
*/
|
||||
|
||||
if (
|
||||
next &&
|
||||
start(next).line === initial.line &&
|
||||
(!next.value || /^(.+?[ \t].+?)/.test(next.value))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
whitelist(initial.line - 1, final.line);
|
||||
}
|
||||
|
||||
visit(ast, 'link', validateLink);
|
||||
visit(ast, 'image', validateLink);
|
||||
|
||||
/*
|
||||
* Iterate over every line, and warn for
|
||||
* violating lines.
|
||||
*/
|
||||
|
||||
while (++index < length) {
|
||||
lineLength = matrix[index].length;
|
||||
|
||||
if (lineLength > style) {
|
||||
file.warn('Line must be at most ' + style + ' characters', {
|
||||
'line': index + 1,
|
||||
'column': lineLength + 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = maximumLineLength;
|
||||
|
@ -19,18 +19,15 @@
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var toString = require('mdast-util-to-string');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = noAutoLinkWithoutProtocol;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
@ -43,6 +40,29 @@ var end = position.end;
|
||||
|
||||
var PROTOCOL = /^[a-z][a-z+.-]+:\/?/i;
|
||||
|
||||
/**
|
||||
* Warn for angle-bracketed links without protocol.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
*/
|
||||
function noAutoLinkWithoutProtocol(ast, file) {
|
||||
visit(ast, 'link', function (node) {
|
||||
var head = start(node.children[0]).column;
|
||||
var tail = end(node.children[node.children.length - 1]).column;
|
||||
var initial = start(node).column;
|
||||
var final = end(node).column;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (initial === head - 1 && final === tail + 1 && !hasProtocol(node)) {
|
||||
file.warn('All automatic links must start with a protocol', node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert `node`s reference starts with a protocol.
|
||||
*
|
||||
@ -50,38 +70,5 @@ var PROTOCOL = /^[a-z][a-z+.-]+:\/?/i;
|
||||
* @return {boolean} - Whether `node` has a protocol.
|
||||
*/
|
||||
function hasProtocol(node) {
|
||||
return PROTOCOL.test(toString(node));
|
||||
return PROTOCOL.test(toString(node));
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn for angle-bracketed links without protocol.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noAutoLinkWithoutProtocol(ast, file, preferred, done) {
|
||||
visit(ast, 'link', function (node) {
|
||||
var head = start(node.children[0]).column;
|
||||
var tail = end(node.children[node.children.length - 1]).column;
|
||||
var initial = start(node).column;
|
||||
var final = end(node).column;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (initial === head - 1 && final === tail + 1 && !hasProtocol(node)) {
|
||||
file.warn('All automatic links must start with a protocol', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noAutoLinkWithoutProtocol;
|
||||
|
@ -19,71 +19,59 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var vfileLocation = require('vfile-location');
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noBlockquoteWithoutCaret;
|
||||
|
||||
/**
|
||||
* Warn when blank lines without carets are found in a
|
||||
* blockquote.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noBlockquoteWithoutCaret(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
var last = contents.length;
|
||||
function noBlockquoteWithoutCaret(ast, file) {
|
||||
var contents = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
var last = contents.length;
|
||||
|
||||
visit(ast, 'blockquote', function (node) {
|
||||
var start = position.start(node).line;
|
||||
var indent = node.position && node.position.indent;
|
||||
visit(ast, 'blockquote', function (node) {
|
||||
var start = position.start(node).line;
|
||||
var indent = node.position && node.position.indent;
|
||||
|
||||
if (position.generated(node) || !indent || !indent.length) {
|
||||
return;
|
||||
if (position.generated(node) || !indent || !indent.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
indent.forEach(function (column, n) {
|
||||
var character;
|
||||
var line = start + n + 1;
|
||||
var offset = location.toOffset({
|
||||
line: line,
|
||||
column: column
|
||||
}) - 1;
|
||||
|
||||
while (++offset < last) {
|
||||
character = contents.charAt(offset);
|
||||
|
||||
if (character === '>') {
|
||||
return;
|
||||
}
|
||||
|
||||
indent.forEach(function (column, n) {
|
||||
var character;
|
||||
var line = start + n + 1;
|
||||
var offset = location.toOffset({
|
||||
'line': line,
|
||||
'column': column
|
||||
}) - 1;
|
||||
/* istanbul ignore else - just for safety */
|
||||
if (character !== ' ' && character !== '\t') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (++offset < last) {
|
||||
character = contents.charAt(offset);
|
||||
|
||||
if (character === '>') {
|
||||
return;
|
||||
}
|
||||
|
||||
/* istanbul ignore else - just for safety */
|
||||
if (character !== ' ' && character !== '\t') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
file.warn('Missing caret in blockquote', {
|
||||
'line': line,
|
||||
'column': column
|
||||
});
|
||||
});
|
||||
file.warn('Missing caret in blockquote', {
|
||||
line: line,
|
||||
column: column
|
||||
});
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noBlockquoteWithoutCaret;
|
||||
|
@ -23,18 +23,15 @@
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
var plural = require('plur');
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = noConsecutiveBlankLines;
|
||||
|
||||
/* Constants. */
|
||||
var MAX = 2;
|
||||
|
||||
/**
|
||||
@ -44,93 +41,69 @@ var MAX = 2;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noConsecutiveBlankLines(ast, file, preferred, done) {
|
||||
/**
|
||||
* Compare the difference between `start` and `end`,
|
||||
* and warn when that difference exceeds `max`.
|
||||
*
|
||||
* @param {Position} start - Initial.
|
||||
* @param {Position} end - Final.
|
||||
* @param {number} max - Threshold.
|
||||
*/
|
||||
function compare(start, end, max) {
|
||||
var diff = end.line - start.line;
|
||||
var word = diff > 0 ? 'before' : 'after';
|
||||
function noConsecutiveBlankLines(ast, file) {
|
||||
visit(ast, function (node) {
|
||||
var children = node.children;
|
||||
var head = children && children[0];
|
||||
var tail = children && children[children.length - 1];
|
||||
|
||||
diff = Math.abs(diff) - max;
|
||||
|
||||
if (diff > 0) {
|
||||
file.warn('Remove ' + diff + ' ' + plural('line', diff) + ' ' + word + ' node', end);
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, function (node) {
|
||||
var children = node.children;
|
||||
var head = children && children[0];
|
||||
var tail = children && children[children.length - 1];
|
||||
if (head && !position.generated(head)) {
|
||||
/* Compare parent and first child. */
|
||||
compare(position.start(node), position.start(head), 0);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
/* Compare between each child. */
|
||||
children.forEach(function (child, index) {
|
||||
var prev = children[index - 1];
|
||||
var max = MAX;
|
||||
|
||||
if (
|
||||
!prev ||
|
||||
position.generated(prev) ||
|
||||
position.generated(child)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (head && !position.generated(head)) {
|
||||
/*
|
||||
* Compare parent and first child.
|
||||
*/
|
||||
|
||||
compare(position.start(node), position.start(head), 0);
|
||||
|
||||
/*
|
||||
* Compare between each child.
|
||||
*/
|
||||
|
||||
children.forEach(function (child, index) {
|
||||
var prev = children[index - 1];
|
||||
var max = MAX;
|
||||
|
||||
if (
|
||||
!prev ||
|
||||
position.generated(prev) ||
|
||||
position.generated(child)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(
|
||||
prev.type === 'list' &&
|
||||
child.type === 'list'
|
||||
) ||
|
||||
(
|
||||
child.type === 'code' &&
|
||||
prev.type === 'list' &&
|
||||
!child.lang
|
||||
)
|
||||
) {
|
||||
max++;
|
||||
}
|
||||
|
||||
compare(position.end(prev), position.start(child), max);
|
||||
});
|
||||
|
||||
/*
|
||||
* Compare parent and last child.
|
||||
*/
|
||||
|
||||
if (tail !== head && !position.generated(tail)) {
|
||||
compare(position.end(node), position.end(tail), 1);
|
||||
}
|
||||
if (
|
||||
(prev.type === 'list' && child.type === 'list') ||
|
||||
(child.type === 'code' && prev.type === 'list' && !child.lang)
|
||||
) {
|
||||
max++;
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
compare(position.end(prev), position.start(child), max);
|
||||
});
|
||||
|
||||
/* Compare parent and last child. */
|
||||
if (tail !== head && !position.generated(tail)) {
|
||||
compare(position.end(node), position.end(tail), 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
/**
|
||||
* Compare the difference between `start` and `end`,
|
||||
* and warn when that difference exceeds `max`.
|
||||
*
|
||||
* @param {Position} start - Initial.
|
||||
* @param {Position} end - Final.
|
||||
* @param {number} max - Threshold.
|
||||
*/
|
||||
function compare(start, end, max) {
|
||||
var diff = end.line - start.line;
|
||||
var word = diff > 0 ? 'before' : 'after';
|
||||
|
||||
diff = Math.abs(diff) - max;
|
||||
|
||||
if (diff > 0) {
|
||||
file.warn('Remove ' + diff + ' ' + plural('line', diff) + ' ' + word + ' node', end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noConsecutiveBlankLines;
|
||||
|
@ -17,15 +17,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var position = require('unist-util-position');
|
||||
var visit = require('unist-util-visit');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noDuplicateDefinitions;
|
||||
|
||||
/**
|
||||
* Warn when definitions with equal content are found.
|
||||
*
|
||||
@ -33,46 +31,38 @@ var visit = require('unist-util-visit');
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noDuplicateDefinitions(ast, file, preferred, done) {
|
||||
var map = {};
|
||||
function noDuplicateDefinitions(ast, file) {
|
||||
var map = {};
|
||||
|
||||
/**
|
||||
* Check `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function validate(node) {
|
||||
var duplicate = map[node.identifier];
|
||||
var pos;
|
||||
visit(ast, 'definition', validate);
|
||||
visit(ast, 'footnoteDefinition', validate);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
if (duplicate && duplicate.type) {
|
||||
pos = position.start(duplicate);
|
||||
/**
|
||||
* Check `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function validate(node) {
|
||||
var duplicate = map[node.identifier];
|
||||
var pos;
|
||||
|
||||
file.warn(
|
||||
'Do not use definitions with the same identifier (' +
|
||||
pos.line + ':' + pos.column + ')',
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
map[node.identifier] = node;
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'definition', validate);
|
||||
visit(ast, 'footnoteDefinition', validate);
|
||||
if (duplicate && duplicate.type) {
|
||||
pos = position.start(duplicate);
|
||||
|
||||
done();
|
||||
file.warn(
|
||||
'Do not use definitions with the same identifier (' +
|
||||
pos.line + ':' + pos.column + ')',
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
map[node.identifier] = node;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noDuplicateDefinitions;
|
||||
|
@ -23,14 +23,14 @@
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var position = require('unist-util-position');
|
||||
var visit = require('unist-util-visit');
|
||||
var toString = require('mdast-util-to-string');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noDuplicateHeadings;
|
||||
|
||||
/**
|
||||
* Warn when headings with equal content are found.
|
||||
*
|
||||
@ -38,39 +38,29 @@ var toString = require('mdast-util-to-string');
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noDuplicateHeadings(ast, file, preferred, done) {
|
||||
var map = {};
|
||||
function noDuplicateHeadings(ast, file) {
|
||||
var map = {};
|
||||
|
||||
visit(ast, 'heading', function (node) {
|
||||
var value = toString(node).toUpperCase();
|
||||
var duplicate = map[value];
|
||||
var pos;
|
||||
visit(ast, 'heading', function (node) {
|
||||
var value = toString(node).toUpperCase();
|
||||
var duplicate = map[value];
|
||||
var pos;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (duplicate && duplicate.type === 'heading') {
|
||||
pos = position.start(duplicate);
|
||||
if (duplicate && duplicate.type === 'heading') {
|
||||
pos = position.start(duplicate);
|
||||
|
||||
file.warn(
|
||||
'Do not use headings with similar content (' +
|
||||
pos.line + ':' + pos.column + ')',
|
||||
node
|
||||
);
|
||||
}
|
||||
file.warn(
|
||||
'Do not use headings with similar content (' +
|
||||
pos.line + ':' + pos.column + ')',
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
map[value] = node;
|
||||
});
|
||||
|
||||
done();
|
||||
map[value] = node;
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noDuplicateHeadings;
|
||||
|
@ -20,51 +20,39 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noEmphasisAsHeading;
|
||||
|
||||
/**
|
||||
* Warn when a section (a new paragraph) is introduced
|
||||
* by emphasis (or strong) and a colon.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noEmphasisAsHeading(ast, file, preferred, done) {
|
||||
visit(ast, 'paragraph', function (node, index, parent) {
|
||||
var children = node.children;
|
||||
var child = children[0];
|
||||
var prev = parent.children[index - 1];
|
||||
var next = parent.children[index + 1];
|
||||
function noEmphasisAsHeading(ast, file) {
|
||||
visit(ast, 'paragraph', function (node, index, parent) {
|
||||
var children = node.children;
|
||||
var child = children[0];
|
||||
var prev = parent.children[index - 1];
|
||||
var next = parent.children[index + 1];
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(!prev || prev.type !== 'heading') &&
|
||||
next &&
|
||||
next.type === 'paragraph' &&
|
||||
children.length === 1 &&
|
||||
(child.type === 'emphasis' || child.type === 'strong')
|
||||
) {
|
||||
file.warn('Don’t use emphasis to introduce a section, use a heading', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (
|
||||
(!prev || prev.type !== 'heading') &&
|
||||
next &&
|
||||
next.type === 'paragraph' &&
|
||||
children.length === 1 &&
|
||||
(child.type === 'emphasis' || child.type === 'strong')
|
||||
) {
|
||||
file.warn('Don’t use emphasis to introduce a section, use a heading', node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noEmphasisAsHeading;
|
||||
|
@ -12,28 +12,19 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
/* Expose. */
|
||||
module.exports = noFileNameArticles;
|
||||
|
||||
/**
|
||||
* Warn when file name start with an article.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noFileNameArticles(ast, file, preferred, done) {
|
||||
var match = file.filename && file.filename.match(/^(the|an?)\b/i);
|
||||
function noFileNameArticles(ast, file) {
|
||||
var match = file.filename && file.filename.match(/^(the|an?)\b/i);
|
||||
|
||||
if (match) {
|
||||
file.warn('Do not start file names with `' + match[0] + '`');
|
||||
}
|
||||
|
||||
done();
|
||||
if (match) {
|
||||
file.warn('Do not start file names with `' + match[0] + '`');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noFileNameArticles;
|
||||
|
@ -12,26 +12,17 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
/* Expose. */
|
||||
module.exports = noFileNameConsecutiveDashes;
|
||||
|
||||
/**
|
||||
* Warn when file names contain consecutive dashes.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noFileNameConsecutiveDashes(ast, file, preferred, done) {
|
||||
if (file.filename && /-{2,}/.test(file.filename)) {
|
||||
file.warn('Do not use consecutive dashes in a file name');
|
||||
}
|
||||
|
||||
done();
|
||||
function noFileNameConsecutiveDashes(ast, file) {
|
||||
if (file.filename && /-{2,}/.test(file.filename)) {
|
||||
file.warn('Do not use consecutive dashes in a file name');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noFileNameConsecutiveDashes;
|
||||
|
@ -21,7 +21,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
/* Expose. */
|
||||
module.exports = noFileNameIrregularCharacters;
|
||||
|
||||
/**
|
||||
* Warn when file names contain characters other than
|
||||
@ -29,28 +30,22 @@
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
* @param {string|RegExp} preferred - RegExp, or string of
|
||||
* characters (in which case it’s wrapped in
|
||||
* `new RegExp('[^' + preferred + ']')`), that matches
|
||||
* characters which should not be allowed.
|
||||
*/
|
||||
function noFileNameIrregularCharacters(ast, file, preferred, done) {
|
||||
var expression = preferred || /[^\\.a-zA-Z0-9-]/;
|
||||
var match;
|
||||
function noFileNameIrregularCharacters(ast, file, preferred) {
|
||||
var expression = preferred || /[^\\.a-zA-Z0-9-]/;
|
||||
var match;
|
||||
|
||||
if (typeof expression === 'string') {
|
||||
expression = new RegExp('[^' + expression + ']');
|
||||
}
|
||||
if (typeof expression === 'string') {
|
||||
expression = new RegExp('[^' + expression + ']');
|
||||
}
|
||||
|
||||
match = file.filename && file.filename.match(expression);
|
||||
match = file.filename && file.filename.match(expression);
|
||||
|
||||
if (match) {
|
||||
file.warn('Do not use `' + match[0] + '` in a file name');
|
||||
}
|
||||
|
||||
done();
|
||||
if (match) {
|
||||
file.warn('Do not use `' + match[0] + '` in a file name');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noFileNameIrregularCharacters;
|
||||
|
@ -13,7 +13,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
/* Expose. */
|
||||
module.exports = noFileNameMixedCase;
|
||||
|
||||
/**
|
||||
* Warn when a file name uses mixed case: both upper- and
|
||||
@ -21,21 +22,11 @@
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noFileNameMixedCase(ast, file, preferred, done) {
|
||||
var name = file.filename;
|
||||
function noFileNameMixedCase(ast, file) {
|
||||
var name = file.filename;
|
||||
|
||||
if (name && !(name === name.toLowerCase() || name === name.toUpperCase())) {
|
||||
file.warn('Do not mix casing in file names');
|
||||
}
|
||||
|
||||
done();
|
||||
if (name && !(name === name.toLowerCase() || name === name.toUpperCase())) {
|
||||
file.warn('Do not mix casing in file names');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noFileNameMixedCase;
|
||||
|
@ -12,26 +12,17 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
/* Expose. */
|
||||
module.exports = noFileNameOuterDashes;
|
||||
|
||||
/**
|
||||
* Warn when file names contain initial or final dashes.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noFileNameOuterDashes(ast, file, preferred, done) {
|
||||
if (file.filename && /^-|-$/.test(file.filename)) {
|
||||
file.warn('Do not use initial or final dashes in a file name');
|
||||
}
|
||||
|
||||
done();
|
||||
function noFileNameOuterDashes(ast, file) {
|
||||
if (file.filename && /^-|-$/.test(file.filename)) {
|
||||
file.warn('Do not use initial or final dashes in a file name');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noFileNameOuterDashes;
|
||||
|
@ -24,21 +24,16 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var style = require('mdast-util-heading-style');
|
||||
var plural = require('plur');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = noHeadingContentIndent;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
@ -49,93 +44,83 @@ var end = position.end;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noHeadingContentIndent(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function noHeadingContentIndent(ast, file) {
|
||||
var contents = file.toString();
|
||||
|
||||
visit(ast, 'heading', function (node) {
|
||||
var depth = node.depth;
|
||||
var children = node.children;
|
||||
var type = style(node, 'atx');
|
||||
var head;
|
||||
var initial;
|
||||
var final;
|
||||
var diff;
|
||||
var word;
|
||||
var index;
|
||||
var char;
|
||||
visit(ast, 'heading', function (node) {
|
||||
var depth = node.depth;
|
||||
var children = node.children;
|
||||
var type = style(node, 'atx');
|
||||
var head;
|
||||
var initial;
|
||||
var final;
|
||||
var diff;
|
||||
var word;
|
||||
var index;
|
||||
var char;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'atx' || type === 'atx-closed') {
|
||||
initial = start(node);
|
||||
index = initial.offset;
|
||||
char = contents.charAt(index);
|
||||
if (type === 'atx' || type === 'atx-closed') {
|
||||
initial = start(node);
|
||||
index = initial.offset;
|
||||
char = contents.charAt(index);
|
||||
|
||||
while (char && char !== '#') {
|
||||
index++;
|
||||
char = contents.charAt(index);
|
||||
}
|
||||
while (char && char !== '#') {
|
||||
index++;
|
||||
char = contents.charAt(index);
|
||||
}
|
||||
|
||||
/* CR/LF bug: wooorm/remark#195. */
|
||||
if (!char) {
|
||||
return;
|
||||
}
|
||||
/* CR/LF bug: wooorm/remark#195. */
|
||||
if (!char) {
|
||||
return;
|
||||
}
|
||||
|
||||
index = depth + (index - initial.offset);
|
||||
head = start(children[0]).column;
|
||||
index = depth + (index - initial.offset);
|
||||
head = start(children[0]).column;
|
||||
|
||||
/*
|
||||
* Ignore empty headings.
|
||||
*/
|
||||
/*
|
||||
* Ignore empty headings.
|
||||
*/
|
||||
|
||||
if (!head) {
|
||||
return;
|
||||
}
|
||||
if (!head) {
|
||||
return;
|
||||
}
|
||||
|
||||
diff = head - initial.column - 1 - index;
|
||||
diff = head - initial.column - 1 - index;
|
||||
|
||||
if (diff) {
|
||||
word = diff > 0 ? 'Remove' : 'Add';
|
||||
diff = Math.abs(diff);
|
||||
if (diff) {
|
||||
word = diff > 0 ? 'Remove' : 'Add';
|
||||
diff = Math.abs(diff);
|
||||
|
||||
file.warn(
|
||||
word + ' ' + diff + ' ' + plural('space', diff) +
|
||||
' before this heading’s content',
|
||||
start(children[0])
|
||||
);
|
||||
}
|
||||
}
|
||||
file.warn(
|
||||
word + ' ' + diff + ' ' + plural('space', diff) +
|
||||
' before this heading’s content',
|
||||
start(children[0])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Closed ATX-heading always must have a space
|
||||
* between their content and the final hashes,
|
||||
* thus, there is no `add x spaces`.
|
||||
*/
|
||||
/*
|
||||
* Closed ATX-heading always must have a space
|
||||
* between their content and the final hashes,
|
||||
* thus, there is no `add x spaces`.
|
||||
*/
|
||||
|
||||
if (type === 'atx-closed') {
|
||||
final = end(children[children.length - 1]);
|
||||
diff = end(node).column - final.column - 1 - depth;
|
||||
if (type === 'atx-closed') {
|
||||
final = end(children[children.length - 1]);
|
||||
diff = end(node).column - final.column - 1 - depth;
|
||||
|
||||
if (diff) {
|
||||
file.warn(
|
||||
'Remove ' + diff + ' ' + plural('space', diff) +
|
||||
' after this heading’s content',
|
||||
final
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (diff) {
|
||||
file.warn(
|
||||
'Remove ' + diff + ' ' + plural('space', diff) +
|
||||
' after this heading’s content',
|
||||
final
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noHeadingContentIndent;
|
||||
|
@ -32,20 +32,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var plural = require('plur');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = noHeadingIndent;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
|
||||
/**
|
||||
@ -54,51 +49,41 @@ var start = position.start;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noHeadingIndent(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
var length = contents.length;
|
||||
function noHeadingIndent(ast, file) {
|
||||
var contents = file.toString();
|
||||
var length = contents.length;
|
||||
|
||||
visit(ast, 'heading', function (node) {
|
||||
var initial = start(node);
|
||||
var begin = initial.offset;
|
||||
var index = begin - 1;
|
||||
var character;
|
||||
var diff;
|
||||
visit(ast, 'heading', function (node) {
|
||||
var initial = start(node);
|
||||
var begin = initial.offset;
|
||||
var index = begin - 1;
|
||||
var character;
|
||||
var diff;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (++index < length) {
|
||||
character = contents.charAt(index);
|
||||
|
||||
if (character !== ' ' && character !== '\t') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
diff = index - begin;
|
||||
|
||||
if (diff) {
|
||||
file.warn(
|
||||
'Remove ' + diff + ' ' + plural('space', diff) +
|
||||
' before this heading',
|
||||
{
|
||||
line: initial.line,
|
||||
column: initial.column + diff
|
||||
}
|
||||
|
||||
while (++index < length) {
|
||||
character = contents.charAt(index);
|
||||
|
||||
if (character !== ' ' && character !== '\t') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
diff = index - begin;
|
||||
|
||||
if (diff) {
|
||||
file.warn(
|
||||
'Remove ' + diff + ' ' + plural('space', diff) +
|
||||
' before this heading',
|
||||
{
|
||||
'line': initial.line,
|
||||
'column': initial.column + diff
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noHeadingIndent;
|
||||
|
@ -29,46 +29,35 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
var toString = require('mdast-util-to-string');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noHeadingPunctuation;
|
||||
|
||||
/**
|
||||
* Warn when headings end in some characters.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {string?} [preferred='\\.,;:!?'] - Group of characters.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noHeadingPunctuation(ast, file, preferred, done) {
|
||||
preferred = typeof preferred === 'string' ? preferred : '\\.,;:!?';
|
||||
function noHeadingPunctuation(ast, file, preferred) {
|
||||
preferred = typeof preferred === 'string' ? preferred : '\\.,;:!?';
|
||||
|
||||
visit(ast, 'heading', function (node) {
|
||||
var value = toString(node);
|
||||
visit(ast, 'heading', function (node) {
|
||||
var value = toString(node);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
value = value.charAt(value.length - 1);
|
||||
value = value.charAt(value.length - 1);
|
||||
|
||||
if (new RegExp('[' + preferred + ']').test(value)) {
|
||||
file.warn('Don’t add a trailing `' + value + '` to headings', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (new RegExp('[' + preferred + ']').test(value)) {
|
||||
file.warn('Don’t add a trailing `' + value + '` to headings', node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noHeadingPunctuation;
|
||||
|
@ -18,15 +18,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = html;
|
||||
|
||||
/**
|
||||
* Warn when HTML nodes are used.
|
||||
*
|
||||
@ -36,13 +34,11 @@ var position = require('unist-util-position');
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function html(ast, file, preferred, done) {
|
||||
visit(ast, 'html', function (node) {
|
||||
if (!position.generated(node) && !/^\s*<!--/.test(node.value)) {
|
||||
file.warn('Do not use HTML in markdown', node);
|
||||
}
|
||||
});
|
||||
visit(ast, 'html', function (node) {
|
||||
if (!position.generated(node) && !/^\s*<!--/.test(node.value)) {
|
||||
file.warn('Do not use HTML in markdown', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
done();
|
||||
}
|
||||
|
||||
module.exports = html;
|
||||
|
@ -18,54 +18,42 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
var toString = require('mdast-util-to-string');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noInlinePadding;
|
||||
|
||||
/**
|
||||
* Warn when inline nodes are padded with spaces between
|
||||
* markers and content.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noInlinePadding(ast, file, preferred, done) {
|
||||
visit(ast, function (node) {
|
||||
var type = node.type;
|
||||
var contents;
|
||||
function noInlinePadding(ast, file) {
|
||||
visit(ast, function (node) {
|
||||
var type = node.type;
|
||||
var contents;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
type === 'emphasis' ||
|
||||
type === 'strong' ||
|
||||
type === 'delete' ||
|
||||
type === 'image' ||
|
||||
type === 'link'
|
||||
) {
|
||||
contents = toString(node);
|
||||
if (
|
||||
type === 'emphasis' ||
|
||||
type === 'strong' ||
|
||||
type === 'delete' ||
|
||||
type === 'image' ||
|
||||
type === 'link'
|
||||
) {
|
||||
contents = toString(node);
|
||||
|
||||
if (contents.charAt(0) === ' ' || contents.charAt(contents.length - 1) === ' ') {
|
||||
file.warn('Don’t pad `' + type + '` with inner spaces', node);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (contents.charAt(0) === ' ' || contents.charAt(contents.length - 1) === ' ') {
|
||||
file.warn('Don’t pad `' + type + '` with inner spaces', node);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noInlinePadding;
|
||||
|
@ -15,27 +15,19 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var toString = require('mdast-util-to-string');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = noLiteralURLs;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
|
||||
/* Constants. */
|
||||
var MAILTO = 'mailto:';
|
||||
|
||||
/**
|
||||
@ -43,35 +35,25 @@ var MAILTO = 'mailto:';
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noLiteralURLs(ast, file, preferred, done) {
|
||||
visit(ast, 'link', function (node) {
|
||||
var head = start(node.children[0]).column;
|
||||
var tail = end(node.children[node.children.length - 1]).column;
|
||||
var initial = start(node).column;
|
||||
var final = end(node).column;
|
||||
var value = toString(node);
|
||||
function noLiteralURLs(ast, file) {
|
||||
visit(ast, 'link', function (node) {
|
||||
var head = start(node.children[0]).column;
|
||||
var tail = end(node.children[node.children.length - 1]).column;
|
||||
var initial = start(node).column;
|
||||
var final = end(node).column;
|
||||
var value = toString(node);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
initial === head &&
|
||||
final === tail &&
|
||||
(value === node.url || value == MAILTO + node.url)
|
||||
) {
|
||||
file.warn('Don’t use literal URLs without angle brackets', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (
|
||||
initial === head &&
|
||||
final === tail &&
|
||||
(value === node.url || value == MAILTO + node.url)
|
||||
) {
|
||||
file.warn('Don’t use literal URLs without angle brackets', node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noLiteralURLs;
|
||||
|
@ -18,15 +18,39 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noMissingBlankLines;
|
||||
|
||||
/**
|
||||
* Warn when there is no empty line between two block
|
||||
* nodes.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
*/
|
||||
function noMissingBlankLines(ast, file) {
|
||||
visit(ast, function (node, index, parent) {
|
||||
var next = parent && parent.children[index + 1];
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
next &&
|
||||
isApplicable(node) &&
|
||||
isApplicable(next) &&
|
||||
position.start(next).line === position.end(node).line + 1
|
||||
) {
|
||||
file.warn('Missing blank line before block node', next);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if `node` is an applicable block-level node.
|
||||
*
|
||||
@ -34,51 +58,15 @@ var position = require('unist-util-position');
|
||||
* @return {boolean} - Whether or not `node` is applicable.
|
||||
*/
|
||||
function isApplicable(node) {
|
||||
return [
|
||||
'paragraph',
|
||||
'blockquote',
|
||||
'heading',
|
||||
'code',
|
||||
'yaml',
|
||||
'html',
|
||||
'list',
|
||||
'table',
|
||||
'thematicBreak'
|
||||
].indexOf(node.type) !== -1;
|
||||
return [
|
||||
'paragraph',
|
||||
'blockquote',
|
||||
'heading',
|
||||
'code',
|
||||
'yaml',
|
||||
'html',
|
||||
'list',
|
||||
'table',
|
||||
'thematicBreak'
|
||||
].indexOf(node.type) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn when there is no empty line between two block
|
||||
* nodes.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noMissingBlankLines(ast, file, preferred, done) {
|
||||
visit(ast, function (node, index, parent) {
|
||||
var next = parent && parent.children[index + 1];
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
next &&
|
||||
isApplicable(node) &&
|
||||
isApplicable(next) &&
|
||||
position.start(next).line === position.end(node).line + 1
|
||||
) {
|
||||
file.warn('Missing blank line before block node', next);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noMissingBlankLines;
|
||||
|
@ -21,15 +21,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noMultipleToplevelHeadings;
|
||||
|
||||
/**
|
||||
* Warn when multiple top-level headings are used.
|
||||
*
|
||||
@ -38,29 +36,25 @@ var position = require('unist-util-position');
|
||||
* @param {number?} [preferred=1] - Top heading level.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noMultipleToplevelHeadings(ast, file, preferred, done) {
|
||||
var style = preferred && preferred !== true ? preferred : 1;
|
||||
var topLevelheading = false;
|
||||
function noMultipleToplevelHeadings(ast, file, preferred) {
|
||||
var style = preferred ? preferred : 1;
|
||||
var topLevelheading = false;
|
||||
|
||||
visit(ast, 'heading', function (node) {
|
||||
var pos;
|
||||
visit(ast, 'heading', function (node) {
|
||||
var pos;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.depth === style) {
|
||||
if (topLevelheading) {
|
||||
pos = position.start(node);
|
||||
if (node.depth === style) {
|
||||
if (topLevelheading) {
|
||||
pos = position.start(node);
|
||||
|
||||
file.warn('Don’t use multiple top level headings (' + pos.line + ':' + pos.column + ')', node);
|
||||
}
|
||||
file.warn('Don’t use multiple top level headings (' + pos.line + ':' + pos.column + ')', node);
|
||||
}
|
||||
|
||||
topLevelheading = node;
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
topLevelheading = node;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = noMultipleToplevelHeadings;
|
||||
|
@ -31,33 +31,28 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/**
|
||||
* List of shell script file extensions (also used as code
|
||||
* flags for syntax highlighting on GitHub):
|
||||
*
|
||||
* @see https://github.com/github/linguist/blob/5bf8cf5/lib/linguist/languages.yml#L3002
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = noShellDollars;
|
||||
|
||||
/* List of shell script file extensions (also used as code
|
||||
* flags for syntax highlighting on GitHub):
|
||||
* https://github.com/github/linguist/blob/5bf8cf5/lib/
|
||||
* linguist/languages.yml#L3002. */
|
||||
var flags = [
|
||||
'sh',
|
||||
'bash',
|
||||
'bats',
|
||||
'cgi',
|
||||
'command',
|
||||
'fcgi',
|
||||
'ksh',
|
||||
'tmux',
|
||||
'tool',
|
||||
'zsh'
|
||||
'sh',
|
||||
'bash',
|
||||
'bats',
|
||||
'cgi',
|
||||
'command',
|
||||
'fcgi',
|
||||
'ksh',
|
||||
'tmux',
|
||||
'tool',
|
||||
'zsh'
|
||||
];
|
||||
|
||||
/**
|
||||
@ -65,39 +60,26 @@ var flags = [
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noShellDollars(ast, file, preferred, done) {
|
||||
visit(ast, 'code', function (node) {
|
||||
var language = node.lang;
|
||||
var value = node.value;
|
||||
var warn;
|
||||
function noShellDollars(ast, file) {
|
||||
visit(ast, 'code', function (node) {
|
||||
var language = node.lang;
|
||||
var value = node.value;
|
||||
var warn;
|
||||
|
||||
if (!language || position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (!language || position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check both known shell-code and unknown code.
|
||||
*/
|
||||
/* Check both known shell-code and unknown code. */
|
||||
if (flags.indexOf(language) !== -1) {
|
||||
warn = value.length && value.split('\n').every(function (line) {
|
||||
return Boolean(!line.trim() || line.match(/^\s*\$\s*/));
|
||||
});
|
||||
|
||||
if (flags.indexOf(language) !== -1) {
|
||||
warn = value.length && value.split('\n').every(function (line) {
|
||||
return Boolean(!line.trim() || line.match(/^\s*\$\s*/));
|
||||
});
|
||||
|
||||
if (warn) {
|
||||
file.warn('Do not use dollar signs before shell-commands', node);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (warn) {
|
||||
file.warn('Do not use dollar signs before shell-commands', node);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noShellDollars;
|
||||
|
@ -19,39 +19,27 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noShortcutReferenceImage;
|
||||
|
||||
/**
|
||||
* Warn when shortcut reference images are used.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noShortcutReferenceImage(ast, file, preferred, done) {
|
||||
visit(ast, 'imageReference', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
function noShortcutReferenceImage(ast, file) {
|
||||
visit(ast, 'imageReference', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.referenceType === 'shortcut') {
|
||||
file.warn('Use the trailing [] on reference images', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (node.referenceType === 'shortcut') {
|
||||
file.warn('Use the trailing [] on reference images', node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noShortcutReferenceImage;
|
||||
|
@ -19,39 +19,27 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noShortcutReferenceLink;
|
||||
|
||||
/**
|
||||
* Warn when shortcut reference links are used.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noShortcutReferenceLink(ast, file, preferred, done) {
|
||||
visit(ast, 'linkReference', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
function noShortcutReferenceLink(ast, file) {
|
||||
visit(ast, 'linkReference', function (node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.referenceType === 'shortcut') {
|
||||
file.warn('Use the trailing [] on reference links', node);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (node.referenceType === 'shortcut') {
|
||||
file.warn('Use the trailing [] on reference links', node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noShortcutReferenceLink;
|
||||
|
@ -19,45 +19,33 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noTableIndentation;
|
||||
|
||||
/**
|
||||
* Warn when a table has a too much indentation.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noTableIndentation(ast, file, preferred, done) {
|
||||
visit(ast, 'table', function (node) {
|
||||
var contents = file.toString();
|
||||
function noTableIndentation(ast, file) {
|
||||
visit(ast, 'table', function (node) {
|
||||
var contents = file.toString();
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
node.children.forEach(function (row) {
|
||||
var fence = contents.slice(position.start(row).offset, position.start(row.children[0]).offset);
|
||||
node.children.forEach(function (row) {
|
||||
var fence = contents.slice(position.start(row).offset, position.start(row.children[0]).offset);
|
||||
|
||||
if (fence.indexOf('|') > 1) {
|
||||
file.warn('Do not indent table rows', row);
|
||||
}
|
||||
});
|
||||
if (fence.indexOf('|') > 1) {
|
||||
file.warn('Do not indent table rows', row);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noTableIndentation;
|
||||
|
@ -20,14 +20,12 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var vfileLocation = require('vfile-location');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noTabs;
|
||||
|
||||
/**
|
||||
* Warn when hard-tabs instead of spaces are used.
|
||||
*
|
||||
@ -37,22 +35,16 @@ var vfileLocation = require('vfile-location');
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noTabs(ast, file, preferred, done) {
|
||||
var content = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
var index = -1;
|
||||
var length = content.length;
|
||||
var content = file.toString();
|
||||
var location = vfileLocation(file);
|
||||
var index = -1;
|
||||
var length = content.length;
|
||||
|
||||
while (++index < length) {
|
||||
if (content.charAt(index) === '\t') {
|
||||
file.warn('Use spaces instead of hard-tabs', location.toPosition(index));
|
||||
}
|
||||
while (++index < length) {
|
||||
if (content.charAt(index) === '\t') {
|
||||
file.warn('Use spaces instead of hard-tabs', location.toPosition(index));
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
done();
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noTabs;
|
||||
|
@ -17,66 +17,56 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var position = require('unist-util-position');
|
||||
var visit = require('unist-util-visit');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noUnusedDefinitions;
|
||||
|
||||
/**
|
||||
* Warn when references to undefined definitions are found.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noUnusedDefinitions(ast, file, preferred, done) {
|
||||
var map = {};
|
||||
function noUnusedDefinitions(ast, file) {
|
||||
var map = {};
|
||||
|
||||
/**
|
||||
* Check `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function mark(node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
visit(ast, 'definition', mark);
|
||||
visit(ast, 'footnoteDefinition', mark);
|
||||
|
||||
map[node.identifier.toUpperCase()] = true;
|
||||
visit(ast, 'imageReference', find);
|
||||
visit(ast, 'linkReference', find);
|
||||
visit(ast, 'footnoteReference', find);
|
||||
|
||||
return;
|
||||
|
||||
/**
|
||||
* Check `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function mark(node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function find(node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
map[node.identifier.toUpperCase()] = true;
|
||||
}
|
||||
|
||||
if (!map[node.identifier.toUpperCase()]) {
|
||||
file.warn('Found reference to undefined definition', node);
|
||||
}
|
||||
/**
|
||||
* Mark `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function find(node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'definition', mark);
|
||||
visit(ast, 'footnoteDefinition', mark);
|
||||
|
||||
visit(ast, 'imageReference', find);
|
||||
visit(ast, 'linkReference', find);
|
||||
visit(ast, 'footnoteReference', find);
|
||||
|
||||
done();
|
||||
if (!map[node.identifier.toUpperCase()]) {
|
||||
file.warn('Found reference to undefined definition', node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noUnusedDefinitions;
|
||||
|
@ -17,76 +17,66 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var position = require('unist-util-position');
|
||||
var visit = require('unist-util-visit');
|
||||
|
||||
/* Expose. */
|
||||
module.exports = noUnusedDefinitions;
|
||||
|
||||
/**
|
||||
* Warn when unused definitions are found.
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function noUnusedDefinitions(ast, file, preferred, done) {
|
||||
var map = {};
|
||||
var identifier;
|
||||
function noUnusedDefinitions(ast, file) {
|
||||
var map = {};
|
||||
var identifier;
|
||||
|
||||
/**
|
||||
* Check `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function find(node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
visit(ast, 'definition', find);
|
||||
visit(ast, 'footnoteDefinition', find);
|
||||
|
||||
map[node.identifier.toUpperCase()] = {
|
||||
'node': node,
|
||||
'used': false
|
||||
};
|
||||
visit(ast, 'imageReference', mark);
|
||||
visit(ast, 'linkReference', mark);
|
||||
visit(ast, 'footnoteReference', mark);
|
||||
|
||||
for (identifier in map) {
|
||||
if (!map[identifier].used) {
|
||||
file.warn('Found unused definition', map[identifier].node);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
/**
|
||||
* Check `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function find(node) {
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function mark(node) {
|
||||
var info = map[node.identifier.toUpperCase()];
|
||||
map[node.identifier.toUpperCase()] = {
|
||||
node: node,
|
||||
used: false
|
||||
};
|
||||
}
|
||||
|
||||
if (position.generated(node) || !info) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Mark `node`.
|
||||
*
|
||||
* @param {Node} node - Node.
|
||||
*/
|
||||
function mark(node) {
|
||||
var info = map[node.identifier.toUpperCase()];
|
||||
|
||||
info.used = true;
|
||||
if (position.generated(node) || !info) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'definition', find);
|
||||
visit(ast, 'footnoteDefinition', find);
|
||||
|
||||
visit(ast, 'imageReference', mark);
|
||||
visit(ast, 'linkReference', mark);
|
||||
visit(ast, 'footnoteReference', mark);
|
||||
|
||||
for (identifier in map) {
|
||||
if (!map[identifier].used) {
|
||||
file.warn('Found unused definition', map[identifier].node);
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
info.used = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = noUnusedDefinitions;
|
||||
|
@ -29,29 +29,21 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = orderedListMarkerStyle;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
|
||||
/*
|
||||
* Valid styles.
|
||||
*/
|
||||
|
||||
/* Valid styles. */
|
||||
var STYLES = {
|
||||
')': true,
|
||||
'.': true,
|
||||
'null': true
|
||||
')': true,
|
||||
'.': true,
|
||||
'null': true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -63,58 +55,44 @@ var STYLES = {
|
||||
* @param {string?} [preferred='consistent'] - Ordered list
|
||||
* marker style, either `'.'` or `')'`, defaulting to the
|
||||
* first found style.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function orderedListMarkerStyle(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function orderedListMarkerStyle(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid ordered list-item marker style `' + preferred + '`: use either `\'.\'` or `\')\'`');
|
||||
done();
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid ordered list-item marker style `' + preferred + '`: use either `\'.\'` or `\')\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
|
||||
if (!node.ordered) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
items.forEach(function (item) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var marker;
|
||||
|
||||
if (!node.ordered) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
items.forEach(function (item) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var marker;
|
||||
marker = contents.slice(initial, final).replace(/\s|\d/g, '');
|
||||
|
||||
if (position.generated(item)) {
|
||||
return;
|
||||
}
|
||||
/* Support checkboxes. */
|
||||
marker = marker.replace(/\[[x ]?\]\s*$/i, '');
|
||||
|
||||
marker = contents.slice(initial, final).replace(/\s|\d/g, '');
|
||||
|
||||
/*
|
||||
* Support checkboxes.
|
||||
*/
|
||||
|
||||
marker = marker.replace(/\[[x ]?\]\s*$/i, '');
|
||||
|
||||
if (!preferred) {
|
||||
preferred = marker;
|
||||
} else if (marker !== preferred) {
|
||||
file.warn('Marker style should be `' + preferred + '`', item);
|
||||
}
|
||||
});
|
||||
if (!preferred) {
|
||||
preferred = marker;
|
||||
} else if (marker !== preferred) {
|
||||
file.warn('Marker style should be `' + preferred + '`', item);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = orderedListMarkerStyle;
|
||||
|
@ -45,29 +45,21 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = orderedListMarkerValue;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
|
||||
/*
|
||||
* Valid styles.
|
||||
*/
|
||||
|
||||
/* Valid styles. */
|
||||
var STYLES = {
|
||||
'ordered': true,
|
||||
'single': true,
|
||||
'one': true
|
||||
ordered: true,
|
||||
single: true,
|
||||
one: true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -79,82 +71,56 @@ var STYLES = {
|
||||
* @param {string?} [preferred='ordered'] - Ordered list
|
||||
* marker value, either `'one'` or `'ordered'`,
|
||||
* defaulting to the latter.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function orderedListMarkerValue(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function orderedListMarkerValue(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
|
||||
preferred = typeof preferred !== 'string' ? 'ordered' : preferred;
|
||||
preferred = typeof preferred === 'string' ? preferred : 'ordered';
|
||||
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid ordered list-item marker value `' + preferred + '`: use either `\'ordered\'` or `\'one\'`');
|
||||
done();
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid ordered list-item marker value `' + preferred + '`: use either `\'ordered\'` or `\'one\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
var shouldBe = (preferred === 'one' ? 1 : node.start) || 1;
|
||||
|
||||
/* Ignore unordered lists. */
|
||||
if (!node.ordered) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
var shouldBe = (preferred === 'one' ? 1 : node.start) || 1;
|
||||
items.forEach(function (item, index) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var marker;
|
||||
|
||||
/*
|
||||
* Ignore unordered lists.
|
||||
*/
|
||||
/* Ignore first list item. */
|
||||
if (index === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!node.ordered) {
|
||||
return;
|
||||
}
|
||||
/* Increase the expected line number when in
|
||||
* `ordered` mode. */
|
||||
if (preferred === 'ordered') {
|
||||
shouldBe++;
|
||||
}
|
||||
|
||||
items.forEach(function (item, index) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var marker;
|
||||
/* Ignore generated nodes. */
|
||||
if (position.generated(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore first list item.
|
||||
*/
|
||||
marker = contents.slice(initial, final).replace(/[\s\.\)]/g, '');
|
||||
|
||||
if (index === 0) {
|
||||
return;
|
||||
}
|
||||
/* Support checkboxes. */
|
||||
marker = Number(marker.replace(/\[[x ]?\]\s*$/i, ''));
|
||||
|
||||
/*
|
||||
* Increase the expected line number when in
|
||||
* `ordered` mode.
|
||||
*/
|
||||
|
||||
if (preferred === 'ordered') {
|
||||
shouldBe++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore generated nodes.
|
||||
*/
|
||||
|
||||
if (position.generated(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
marker = contents.slice(initial, final).replace(/[\s\.\)]/g, '');
|
||||
|
||||
/*
|
||||
* Support checkboxes.
|
||||
*/
|
||||
|
||||
marker = Number(marker.replace(/\[[x ]?\]\s*$/i, ''));
|
||||
|
||||
if (marker !== shouldBe) {
|
||||
file.warn('Marker should be `' + shouldBe + '`, was `' + marker + '`', item);
|
||||
}
|
||||
});
|
||||
if (marker !== shouldBe) {
|
||||
file.warn('Marker should be `' + shouldBe + '`, was `' + marker + '`', item);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = orderedListMarkerValue;
|
||||
|
@ -24,33 +24,17 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = ruleStyle;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
/**
|
||||
* Warn when a given style is invalid.
|
||||
*
|
||||
* @param {*} style - `*`, `_`, ` ` (space), or `-`.
|
||||
* @return {boolean} - Whether or not `style` is a
|
||||
* valid rule style.
|
||||
*/
|
||||
function validateRuleStyle(style) {
|
||||
return style === null || !/[^-_* ]/.test(style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn when the horizontal rules violate a given or
|
||||
* detected style.
|
||||
@ -59,45 +43,45 @@ function validateRuleStyle(style) {
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {string?} [preferred='consistent'] - A valid
|
||||
* horizontal rule, defaulting to the first found style.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function ruleStyle(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function ruleStyle(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
|
||||
if (validateRuleStyle(preferred) !== true) {
|
||||
file.fail('Invalid preferred rule-style: provide a valid markdown rule, or `\'consistent\'`');
|
||||
done();
|
||||
if (validateRuleStyle(preferred) !== true) {
|
||||
file.fail('Invalid preferred rule-style: provide a valid markdown rule, or `\'consistent\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
visit(ast, 'thematicBreak', function (node) {
|
||||
var initial = start(node).offset;
|
||||
var final = end(node).offset;
|
||||
var hr;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'thematicBreak', function (node) {
|
||||
var initial = start(node).offset;
|
||||
var final = end(node).offset;
|
||||
var hr;
|
||||
hr = contents.slice(initial, final);
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = contents.slice(initial, final);
|
||||
|
||||
if (preferred) {
|
||||
if (hr !== preferred) {
|
||||
file.warn('Rules should use `' + preferred + '`', node);
|
||||
}
|
||||
} else {
|
||||
preferred = hr;
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
if (preferred) {
|
||||
if (hr !== preferred) {
|
||||
file.warn('Rules should use `' + preferred + '`', node);
|
||||
}
|
||||
} else {
|
||||
preferred = hr;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
/**
|
||||
* Warn when a given style is invalid.
|
||||
*
|
||||
* @param {*} style - `*`, `_`, ` ` (space), or `-`.
|
||||
* @return {boolean} - Whether or not `style` is a
|
||||
* valid rule style.
|
||||
*/
|
||||
|
||||
module.exports = ruleStyle;
|
||||
function validateRuleStyle(style) {
|
||||
return style === null || !/[^-_* ]/.test(style);
|
||||
}
|
||||
|
@ -24,23 +24,18 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Map of valid markers.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = strongMarker;
|
||||
|
||||
/* Map of valid markers. */
|
||||
var MARKERS = {
|
||||
'*': true,
|
||||
'_': true,
|
||||
'null': true
|
||||
'*': true,
|
||||
'_': true,
|
||||
'null': true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -50,36 +45,28 @@ var MARKERS = {
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {string?} [preferred='consistent'] - Preferred
|
||||
* marker, either `"*"` or `"_"`, or `"consistent"`.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function strongMarker(ast, file, preferred, done) {
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
function strongMarker(ast, file, preferred) {
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
|
||||
if (MARKERS[preferred] !== true) {
|
||||
file.fail('Invalid strong marker `' + preferred + '`: use either `\'consistent\'`, `\'*\'`, or `\'_\'`');
|
||||
} else {
|
||||
visit(ast, 'strong', function (node) {
|
||||
var marker = file.toString().charAt(position.start(node).offset);
|
||||
if (MARKERS[preferred] !== true) {
|
||||
file.fail('Invalid strong marker `' + preferred + '`: use either `\'consistent\'`, `\'*\'`, or `\'_\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
visit(ast, 'strong', function (node) {
|
||||
var marker = file.toString().charAt(position.start(node).offset);
|
||||
|
||||
if (preferred) {
|
||||
if (marker !== preferred) {
|
||||
file.warn('Strong should use `' + preferred + '` as a marker', node);
|
||||
}
|
||||
} else {
|
||||
preferred = marker;
|
||||
}
|
||||
});
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
done();
|
||||
if (preferred) {
|
||||
if (marker !== preferred) {
|
||||
file.warn('Strong should use `' + preferred + '` as a marker', node);
|
||||
}
|
||||
} else {
|
||||
preferred = marker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = strongMarker;
|
||||
|
@ -31,30 +31,24 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
/* eslint-disable max-params */
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = tableCellPadding;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
/*
|
||||
* Valid styles.
|
||||
*/
|
||||
|
||||
/* Valid styles. */
|
||||
var STYLES = {
|
||||
'null': true,
|
||||
'padded': true,
|
||||
'compact': true
|
||||
null: true,
|
||||
padded: true,
|
||||
compact: true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -66,121 +60,113 @@ var STYLES = {
|
||||
* at least a space), `compact` (for no spaces when
|
||||
* possible), or `consistent`, which defaults to the
|
||||
* first found style.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function tableCellPadding(ast, file, preferred, done) {
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
function tableCellPadding(ast, file, preferred) {
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid table-cell-padding style `' + preferred + '`');
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid table-cell-padding style `' + preferred + '`');
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'table', function (node) {
|
||||
var children = node.children;
|
||||
var contents = file.toString();
|
||||
var starts = [];
|
||||
var ends = [];
|
||||
var locations;
|
||||
var positions;
|
||||
var style;
|
||||
var type;
|
||||
var warning;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'table', function (node) {
|
||||
var children = node.children;
|
||||
var contents = file.toString();
|
||||
var starts = [];
|
||||
var ends = [];
|
||||
var locations;
|
||||
var positions;
|
||||
var style;
|
||||
var type;
|
||||
var warning;
|
||||
/**
|
||||
* Check a fence. Checks both its initial spacing
|
||||
* (between a cell and the fence), and its final
|
||||
* spacing (between the fence and the next cell).
|
||||
*
|
||||
* @param {number} initial - Starting index.
|
||||
* @param {number} final - Closing index.
|
||||
* @param {Node} cell - Table cell.
|
||||
* @param {Node?} next - Following cell.
|
||||
* @param {number} index - Position of `cell` in
|
||||
* its parent.
|
||||
*/
|
||||
function check(initial, final, cell, next, index) {
|
||||
var fence = contents.slice(initial, final);
|
||||
var pos = fence.indexOf('|');
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
if (
|
||||
cell &&
|
||||
pos !== -1 &&
|
||||
(ends[index] === undefined || pos < ends[index])
|
||||
) {
|
||||
ends[index] = pos;
|
||||
}
|
||||
|
||||
if (next && pos !== -1) {
|
||||
pos = fence.length - pos - 1;
|
||||
|
||||
if (starts[index + 1] === undefined || pos < starts[index + 1]) {
|
||||
starts[index + 1] = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a fence. Checks both its initial spacing
|
||||
* (between a cell and the fence), and its final
|
||||
* spacing (between the fence and the next cell).
|
||||
*
|
||||
* @param {number} initial - Starting index.
|
||||
* @param {number} final - Closing index.
|
||||
* @param {Node} cell - Table cell.
|
||||
* @param {Node?} next - Following cell.
|
||||
* @param {number} index - Position of `cell` in
|
||||
* its parent.
|
||||
*/
|
||||
function check(initial, final, cell, next, index) {
|
||||
var fence = contents.slice(initial, final);
|
||||
var pos = fence.indexOf('|');
|
||||
children.forEach(function (row) {
|
||||
var cells = row.children;
|
||||
|
||||
if (
|
||||
cell &&
|
||||
pos !== -1 &&
|
||||
(
|
||||
ends[index] === undefined ||
|
||||
pos < ends[index]
|
||||
)
|
||||
) {
|
||||
ends[index] = pos;
|
||||
}
|
||||
check(start(row).offset, start(cells[0]).offset, null, cells[0], -1);
|
||||
|
||||
if (next && pos !== -1) {
|
||||
pos = fence.length - pos - 1;
|
||||
cells.forEach(function (cell, index) {
|
||||
var next = cells[index + 1] || null;
|
||||
var final = start(next).offset || end(row).offset;
|
||||
|
||||
if (starts[index + 1] === undefined || pos < starts[index + 1]) {
|
||||
starts[index + 1] = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
children.forEach(function (row) {
|
||||
var cells = row.children;
|
||||
|
||||
check(start(row).offset, start(cells[0]).offset, null, cells[0], -1);
|
||||
|
||||
cells.forEach(function (cell, index) {
|
||||
var next = cells[index + 1] || null;
|
||||
var final = start(next).offset || end(row).offset;
|
||||
|
||||
check(end(cell).offset, final, cell, next, index);
|
||||
});
|
||||
});
|
||||
|
||||
positions = starts.concat(ends);
|
||||
|
||||
style = preferred === 'padded' ? 1 : preferred === 'compact' ? 0 : null;
|
||||
|
||||
if (preferred === 'padded') {
|
||||
style = 1;
|
||||
} else if (preferred === 'compact') {
|
||||
style = 0;
|
||||
} else {
|
||||
positions.some(function (pos) {
|
||||
/*
|
||||
* `some` skips non-existant indices, so
|
||||
* there's no need to check for `!isNaN`.
|
||||
*/
|
||||
|
||||
style = Math.min(pos, 1);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
locations = children[0].children.map(function (cell) {
|
||||
return start(cell);
|
||||
}).concat(children[0].children.map(function (cell) {
|
||||
return end(cell);
|
||||
}));
|
||||
|
||||
type = style === 1 ? 'padded' : 'compact';
|
||||
warning = 'Cell should be ' + type + ', isn’t';
|
||||
|
||||
positions.forEach(function (diff, index) {
|
||||
if (diff !== style && diff !== undefined && diff !== null) {
|
||||
file.warn(warning, locations[index]);
|
||||
}
|
||||
});
|
||||
check(end(cell).offset, final, cell, next, index);
|
||||
});
|
||||
});
|
||||
|
||||
done();
|
||||
positions = starts.concat(ends);
|
||||
|
||||
if (preferred === 'padded') {
|
||||
style = 1;
|
||||
} else if (preferred === 'compact') {
|
||||
style = 0;
|
||||
} else {
|
||||
style = null;
|
||||
}
|
||||
|
||||
if (preferred === 'padded') {
|
||||
style = 1;
|
||||
} else if (preferred === 'compact') {
|
||||
style = 0;
|
||||
} else {
|
||||
positions.some(function (pos) {
|
||||
/* `some` skips non-existant indices, so
|
||||
* there's no need to check for `!isNaN`. */
|
||||
style = Math.min(pos, 1);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
locations = children[0].children.map(function (cell) {
|
||||
return start(cell);
|
||||
}).concat(children[0].children.map(function (cell) {
|
||||
return end(cell);
|
||||
}));
|
||||
|
||||
type = style === 1 ? 'padded' : 'compact';
|
||||
warning = 'Cell should be ' + type + ', isn’t';
|
||||
|
||||
positions.forEach(function (diff, index) {
|
||||
if (diff !== style && diff !== undefined && diff !== null) {
|
||||
file.warn(warning, locations[index]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = tableCellPadding;
|
||||
|
@ -19,19 +19,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = tablePipeAlignment;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
@ -40,69 +35,59 @@ var end = position.end;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function tablePipeAlignment(ast, file, preferred, done) {
|
||||
visit(ast, 'table', function (node) {
|
||||
var contents = file.toString();
|
||||
var indices = [];
|
||||
var offset;
|
||||
var line;
|
||||
function tablePipeAlignment(ast, file) {
|
||||
visit(ast, 'table', function (node) {
|
||||
var contents = file.toString();
|
||||
var indices = [];
|
||||
var offset;
|
||||
var line;
|
||||
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all pipes after each column are at
|
||||
* aligned.
|
||||
*
|
||||
* @param {number} initial - Starting index.
|
||||
* @param {number} final - Closing index.
|
||||
* @param {number} index - Position of cell in
|
||||
* its parent.
|
||||
*/
|
||||
function check(initial, final, index) {
|
||||
var pos = initial + contents.slice(initial, final).indexOf('|') - offset + 1;
|
||||
/**
|
||||
* Check all pipes after each column are at
|
||||
* aligned.
|
||||
*
|
||||
* @param {number} initial - Starting index.
|
||||
* @param {number} final - Closing index.
|
||||
* @param {number} index - Position of cell in
|
||||
* its parent.
|
||||
*/
|
||||
function check(initial, final, index) {
|
||||
var pos = initial + contents.slice(initial, final).indexOf('|') - offset + 1;
|
||||
|
||||
if (indices[index] === undefined || indices[index] === null) {
|
||||
indices[index] = pos;
|
||||
} else if (pos !== indices[index]) {
|
||||
file.warn('Misaligned table fence', {
|
||||
'start': {
|
||||
'line': line,
|
||||
'column': pos
|
||||
},
|
||||
'end': {
|
||||
'line': line,
|
||||
'column': pos + 1
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
node.children.forEach(function (row) {
|
||||
var cells = row.children;
|
||||
|
||||
line = start(row).line;
|
||||
offset = start(row).offset;
|
||||
|
||||
check(start(row).offset, start(cells[0]).offset, 0);
|
||||
|
||||
row.children.forEach(function (cell, index) {
|
||||
var next = start(cells[index + 1]).offset || end(row).offset;
|
||||
|
||||
check(end(cell).offset, next, index + 1);
|
||||
});
|
||||
if (indices[index] === undefined || indices[index] === null) {
|
||||
indices[index] = pos;
|
||||
} else if (pos !== indices[index]) {
|
||||
file.warn('Misaligned table fence', {
|
||||
start: {
|
||||
line: line,
|
||||
column: pos
|
||||
},
|
||||
end: {
|
||||
line: line,
|
||||
column: pos + 1
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
node.children.forEach(function (row) {
|
||||
var cells = row.children;
|
||||
|
||||
line = start(row).line;
|
||||
offset = start(row).offset;
|
||||
|
||||
check(start(row).offset, start(cells[0]).offset, 0);
|
||||
|
||||
row.children.forEach(function (cell, index) {
|
||||
var next = start(cells[index + 1]).offset || end(row).offset;
|
||||
|
||||
check(end(cell).offset, next, index + 1);
|
||||
});
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = tablePipeAlignment;
|
||||
|
@ -19,19 +19,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = tablePipes;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
var end = position.end;
|
||||
|
||||
@ -40,39 +35,29 @@ var end = position.end;
|
||||
*
|
||||
* @param {Node} ast - Root node.
|
||||
* @param {File} file - Virtual file.
|
||||
* @param {*} preferred - Ignored.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function tablePipes(ast, file, preferred, done) {
|
||||
visit(ast, 'table', function (node) {
|
||||
var contents = file.toString();
|
||||
function tablePipes(ast, file) {
|
||||
visit(ast, 'table', function (node) {
|
||||
var contents = file.toString();
|
||||
|
||||
node.children.forEach(function (row) {
|
||||
var cells = row.children;
|
||||
var head = cells[0];
|
||||
var tail = cells[cells.length - 1];
|
||||
var initial = contents.slice(start(row).offset, start(head).offset);
|
||||
var final = contents.slice(end(tail).offset, end(row).offset);
|
||||
node.children.forEach(function (row) {
|
||||
var cells = row.children;
|
||||
var head = cells[0];
|
||||
var tail = cells[cells.length - 1];
|
||||
var initial = contents.slice(start(row).offset, start(head).offset);
|
||||
var final = contents.slice(end(tail).offset, end(row).offset);
|
||||
|
||||
if (position.generated(row)) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(row)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (initial.indexOf('|') === -1) {
|
||||
file.warn('Missing initial pipe in table fence', start(row));
|
||||
}
|
||||
if (initial.indexOf('|') === -1) {
|
||||
file.warn('Missing initial pipe in table fence', start(row));
|
||||
}
|
||||
|
||||
if (final.indexOf('|') === -1) {
|
||||
file.warn('Missing final pipe in table fence', end(row));
|
||||
}
|
||||
});
|
||||
if (final.indexOf('|') === -1) {
|
||||
file.warn('Missing final pipe in table fence', end(row));
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = tablePipes;
|
||||
|
@ -33,30 +33,22 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env commonjs */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
var position = require('unist-util-position');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
/* Expose. */
|
||||
module.exports = unorderedListMarkerStyle;
|
||||
|
||||
/* Methods. */
|
||||
var start = position.start;
|
||||
|
||||
/*
|
||||
* Valid styles.
|
||||
*/
|
||||
|
||||
/* Valid styles. */
|
||||
var STYLES = {
|
||||
'-': true,
|
||||
'*': true,
|
||||
'+': true,
|
||||
'null': true
|
||||
'-': true,
|
||||
'*': true,
|
||||
'+': true,
|
||||
'null': true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -68,58 +60,44 @@ var STYLES = {
|
||||
* @param {string?} [preferred='consistent'] - Unordered
|
||||
* list marker style, either `'-'`, `'*'`, or `'+'`,
|
||||
* defaulting to the first found style.
|
||||
* @param {Function} done - Callback.
|
||||
*/
|
||||
function unorderedListMarkerStyle(ast, file, preferred, done) {
|
||||
var contents = file.toString();
|
||||
function unorderedListMarkerStyle(ast, file, preferred) {
|
||||
var contents = file.toString();
|
||||
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
|
||||
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid unordered list-item marker style `' + preferred + '`: use either `\'-\'`, `\'*\'`, or `\'+\'`');
|
||||
done();
|
||||
if (STYLES[preferred] !== true) {
|
||||
file.fail('Invalid unordered list-item marker style `' + preferred + '`: use either `\'-\'`, `\'*\'`, or `\'+\'`');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
|
||||
if (node.ordered) {
|
||||
return;
|
||||
}
|
||||
|
||||
visit(ast, 'list', function (node) {
|
||||
var items = node.children;
|
||||
items.forEach(function (item) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var marker;
|
||||
|
||||
if (node.ordered) {
|
||||
return;
|
||||
}
|
||||
if (position.generated(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
items.forEach(function (item) {
|
||||
var head = item.children[0];
|
||||
var initial = start(item).offset;
|
||||
var final = start(head).offset;
|
||||
var marker;
|
||||
marker = contents.slice(initial, final).replace(/\s/g, '');
|
||||
|
||||
if (position.generated(item)) {
|
||||
return;
|
||||
}
|
||||
/* Support checkboxes. */
|
||||
marker = marker.replace(/\[[x ]?\]\s*$/i, '');
|
||||
|
||||
marker = contents.slice(initial, final).replace(/\s/g, '');
|
||||
|
||||
/*
|
||||
* Support checkboxes.
|
||||
*/
|
||||
|
||||
marker = marker.replace(/\[[x ]?\]\s*$/i, '');
|
||||
|
||||
if (!preferred) {
|
||||
preferred = marker;
|
||||
} else if (marker !== preferred) {
|
||||
file.warn('Marker style should be `' + preferred + '`', item);
|
||||
}
|
||||
});
|
||||
if (!preferred) {
|
||||
preferred = marker;
|
||||
} else if (marker !== preferred) {
|
||||
file.warn('Marker style should be `' + preferred + '`', item);
|
||||
}
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose.
|
||||
*/
|
||||
|
||||
module.exports = unorderedListMarkerStyle;
|
||||
|
43
package.json
43
package.json
@ -40,11 +40,9 @@
|
||||
"devDependencies": {
|
||||
"browserify": "^13.0.0",
|
||||
"dox": "^0.8.0",
|
||||
"eslint": "^2.0.0",
|
||||
"esmangle": "^1.0.0",
|
||||
"istanbul": "^0.4.0",
|
||||
"jscs": "^3.0.0",
|
||||
"jscs-jsdoc": "^2.0.0",
|
||||
"mocha": "^2.0.0",
|
||||
"remark": "^5.0.0",
|
||||
"remark-cli": "^1.0.0",
|
||||
"remark-comment-config": "^4.0.0",
|
||||
@ -60,11 +58,44 @@
|
||||
"build-bundle": "browserify index.js --bare -s remarkLint > remark-lint.js",
|
||||
"build-mangle": "esmangle remark-lint.js > remark-lint.min.js",
|
||||
"build": "npm run build-rules && npm run build-md && npm run build-bundle && npm run build-mangle",
|
||||
"lint-api": "eslint .",
|
||||
"lint-style": "jscs . --reporter inline",
|
||||
"lint": "npm run lint-api && npm run lint-style",
|
||||
"lint": "xo",
|
||||
"test-api": "mocha --check-leaks test/index.js",
|
||||
"test-coverage": "istanbul cover _mocha -- test/index.js",
|
||||
"test": "npm run build && npm run lint && npm run test-coverage"
|
||||
},
|
||||
"nyc": {
|
||||
"check-coverage": true,
|
||||
"lines": 100,
|
||||
"functions": 100,
|
||||
"branches": 100
|
||||
},
|
||||
"xo": {
|
||||
"space": true,
|
||||
"rules": {
|
||||
"guard-for-in": "off",
|
||||
"no-eq-null": "off",
|
||||
"eqeqeq": "off"
|
||||
},
|
||||
"ignores": [
|
||||
"remark-lint.js",
|
||||
"remark-lint.min.js"
|
||||
]
|
||||
},
|
||||
"remarkConfig": {
|
||||
"output": true,
|
||||
"plugins": {
|
||||
"comment-config": null,
|
||||
"github": null,
|
||||
"toc": {
|
||||
"tight": true
|
||||
},
|
||||
"./": {
|
||||
"no-missing-blank-lines": false
|
||||
},
|
||||
"validate-links": null
|
||||
},
|
||||
"settings": {
|
||||
"bullet": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env node */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var dox = require('dox');
|
||||
@ -24,12 +19,144 @@ var toc = require('remark-toc');
|
||||
var rules = require('../lib/rules');
|
||||
var additional = require('./additional.json');
|
||||
|
||||
/*
|
||||
* Methods.
|
||||
*/
|
||||
|
||||
/* Methods. */
|
||||
var exists = fs.existsSync;
|
||||
|
||||
var children = [];
|
||||
|
||||
/* Add main heading. */
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 1,
|
||||
children: [{
|
||||
type: 'text',
|
||||
value: 'List of Rules'
|
||||
}]
|
||||
});
|
||||
|
||||
/* Add main description. */
|
||||
children.push(
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{
|
||||
type: 'text',
|
||||
value: 'This document describes all available rules, what they\n' +
|
||||
'check for, examples of what they warn for, and how to\n' +
|
||||
'fix their warnings.'
|
||||
}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'See the readme for a '
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
url: 'https://github.com/wooorm/remark-lint#list-of-external-rules',
|
||||
children: [{
|
||||
type: 'text',
|
||||
value: 'list of external rules'
|
||||
}]
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: '.'
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
/* Add the rules heading. */
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{
|
||||
type: 'text',
|
||||
value: 'Rules'
|
||||
}]
|
||||
});
|
||||
|
||||
/* Add a section on how to turn of rules. */
|
||||
children.push({
|
||||
type: 'paragraph',
|
||||
children: [{
|
||||
type: 'text',
|
||||
value: 'Remember that rules can always be turned off by\n' +
|
||||
'passing false. In addition, when reset is given, values can\n' +
|
||||
'be null or undefined in order to be ignored.'
|
||||
}]
|
||||
});
|
||||
|
||||
/* Add the table-of-contents heading. */
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 3,
|
||||
children: [{
|
||||
type: 'text',
|
||||
value: 'Table of Contents'
|
||||
}]
|
||||
});
|
||||
|
||||
/* Add rules. */
|
||||
Object.keys(additional).sort()
|
||||
.concat(Object.keys(rules).sort())
|
||||
.forEach(function (ruleId) {
|
||||
var description;
|
||||
var filePath;
|
||||
var example;
|
||||
var code;
|
||||
var tags;
|
||||
|
||||
filePath = path.join('lib', 'rules', ruleId + '.js');
|
||||
|
||||
if (exists(filePath)) {
|
||||
code = fs.readFileSync(filePath, 'utf-8');
|
||||
tags = dox.parseComments(code)[0].tags;
|
||||
description = find(tags, 'fileoverview');
|
||||
example = find(tags, 'example');
|
||||
|
||||
if (!description) {
|
||||
throw new Error(ruleId + ' is missing a `@fileoverview`');
|
||||
}
|
||||
|
||||
description = description.string;
|
||||
example = example && example.string;
|
||||
} else {
|
||||
description = additional[ruleId].description;
|
||||
example = additional[ruleId].example;
|
||||
}
|
||||
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 3,
|
||||
children: [{
|
||||
type: 'text',
|
||||
value: ruleId
|
||||
}]
|
||||
});
|
||||
|
||||
if (example) {
|
||||
children.push({
|
||||
type: 'code',
|
||||
lang: 'md',
|
||||
value: example
|
||||
});
|
||||
}
|
||||
|
||||
children = children.concat(remark().parse(description).children);
|
||||
});
|
||||
|
||||
/* Node. */
|
||||
var node = {type: 'root', children: children};
|
||||
|
||||
/* Add toc. */
|
||||
remark().use(toc).run(node);
|
||||
|
||||
/* Write. */
|
||||
fs.writeFileSync('doc/rules.md', remark().stringify(node));
|
||||
|
||||
/**
|
||||
* Find the first tag in `tags` with a type set to `key`.
|
||||
*
|
||||
@ -38,180 +165,17 @@ var exists = fs.existsSync;
|
||||
* @return {Object?} - Tag, when found.
|
||||
*/
|
||||
function find(tags, key) {
|
||||
var value = null;
|
||||
var value = null;
|
||||
|
||||
tags.some(function (tag) {
|
||||
if (tag && tag.type === key) {
|
||||
value = tag;
|
||||
tags.some(function (tag) {
|
||||
if (tag && tag.type === key) {
|
||||
value = tag;
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
return value;
|
||||
return false;
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
var children = [];
|
||||
|
||||
/*
|
||||
* Add main heading.
|
||||
*/
|
||||
|
||||
children.push({
|
||||
'type': 'heading',
|
||||
'depth': 1,
|
||||
'children': [{
|
||||
'type': 'text',
|
||||
'value': 'List of Rules'
|
||||
}]
|
||||
});
|
||||
|
||||
/*
|
||||
* Add main description.
|
||||
*/
|
||||
|
||||
children.push(
|
||||
{
|
||||
'type': 'paragraph',
|
||||
'children': [{
|
||||
'type': 'text',
|
||||
'value': 'This document describes all available rules, what they\n' +
|
||||
'check for, examples of what they warn for, and how to\n' +
|
||||
'fix their warnings.'
|
||||
}]
|
||||
},
|
||||
{
|
||||
'type': 'paragraph',
|
||||
'children': [
|
||||
{
|
||||
'type': 'text',
|
||||
'value': 'See the readme for a '
|
||||
},
|
||||
{
|
||||
'type': 'link',
|
||||
'url': 'https://github.com/wooorm/remark-lint#list-of-external-rules',
|
||||
'children': [{
|
||||
'type': 'text',
|
||||
'value': 'list of external rules'
|
||||
}]
|
||||
},
|
||||
{
|
||||
'type': 'text',
|
||||
'value': '.'
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
* Add the rules heading.
|
||||
*/
|
||||
|
||||
children.push({
|
||||
'type': 'heading',
|
||||
'depth': 2,
|
||||
'children': [{
|
||||
'type': 'text',
|
||||
'value': 'Rules'
|
||||
}]
|
||||
});
|
||||
|
||||
/*
|
||||
* Add a section on how to turn of rules.
|
||||
*/
|
||||
|
||||
children.push({
|
||||
'type': 'paragraph',
|
||||
'children': [{
|
||||
'type': 'text',
|
||||
'value': 'Remember that rules can always be turned off by\n' +
|
||||
'passing false. In addition, when reset is given, values can\n' +
|
||||
'be null or undefined in order to be ignored.'
|
||||
}]
|
||||
});
|
||||
|
||||
/*
|
||||
* Add the table-of-contents heading.
|
||||
*/
|
||||
|
||||
children.push({
|
||||
'type': 'heading',
|
||||
'depth': 3,
|
||||
'children': [{
|
||||
'type': 'text',
|
||||
'value': 'Table of Contents'
|
||||
}]
|
||||
});
|
||||
|
||||
/*
|
||||
* Add rules.
|
||||
*/
|
||||
|
||||
Object.keys(additional).sort()
|
||||
.concat(Object.keys(rules).sort())
|
||||
.forEach(function (ruleId) {
|
||||
var description;
|
||||
var filePath;
|
||||
var example;
|
||||
var code;
|
||||
var tags;
|
||||
|
||||
filePath = path.join('lib', 'rules', ruleId + '.js');
|
||||
|
||||
if (exists(filePath)) {
|
||||
code = fs.readFileSync(filePath, 'utf-8');
|
||||
tags = dox.parseComments(code)[0].tags;
|
||||
description = find(tags, 'fileoverview');
|
||||
example = find(tags, 'example');
|
||||
|
||||
if (!description) {
|
||||
throw new Error(ruleId + ' is missing a `@fileoverview`');
|
||||
}
|
||||
|
||||
description = description.string;
|
||||
example = example && example.string;
|
||||
} else {
|
||||
description = additional[ruleId].description;
|
||||
example = additional[ruleId].example;
|
||||
}
|
||||
|
||||
children.push({
|
||||
'type': 'heading',
|
||||
'depth': 3,
|
||||
'children': [{
|
||||
'type': 'text',
|
||||
'value': ruleId
|
||||
}]
|
||||
});
|
||||
|
||||
if (example) {
|
||||
children.push({
|
||||
'type': 'code',
|
||||
'lang': 'md',
|
||||
'value': example
|
||||
});
|
||||
}
|
||||
|
||||
children = children.concat(remark().parse(description).children);
|
||||
});
|
||||
|
||||
/*
|
||||
* Node.
|
||||
*/
|
||||
|
||||
var node = {
|
||||
'type': 'root',
|
||||
'children': children
|
||||
};
|
||||
|
||||
/*
|
||||
* Add toc.
|
||||
*/
|
||||
|
||||
remark().use(toc).run(node);
|
||||
|
||||
/*
|
||||
* Write.
|
||||
*/
|
||||
|
||||
fs.writeFileSync('doc/rules.md', remark().stringify(node));
|
||||
|
@ -10,12 +10,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/* eslint-env node */
|
||||
|
||||
/*
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
/* Dependencies. */
|
||||
var visit = require('unist-util-visit');
|
||||
|
||||
/**
|
||||
@ -24,9 +19,9 @@ var visit = require('unist-util-visit');
|
||||
* @param {Node} ast - Root node.
|
||||
*/
|
||||
function transformer(ast) {
|
||||
visit(ast, function (node) {
|
||||
node.position = undefined;
|
||||
});
|
||||
visit(ast, function (node) {
|
||||
node.position = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,7 +30,7 @@ function transformer(ast) {
|
||||
* @return {Function} - See `transformer`.
|
||||
*/
|
||||
function attacher() {
|
||||
return transformer;
|
||||
return transformer;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user