diff --git a/.editorconfig b/.editorconfig index db57c652..c6c8b362 100644 --- a/.editorconfig +++ b/.editorconfig @@ -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 diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 7a7d04d7..00000000 --- a/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -coverage/ -remark-lint.js -remark-lint.min.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 4426f37f..00000000 --- a/.eslintrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "eslint:recommended", - "rules": { - "quotes": [2, "single"] - } -} diff --git a/.jscs.json b/.jscs.json deleted file mode 100644 index ad4b1400..00000000 --- a/.jscs.json +++ /dev/null @@ -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 - } -} diff --git a/.remarkignore b/.remarkignore index c158840e..9daeafb9 100644 --- a/.remarkignore +++ b/.remarkignore @@ -1,4 +1 @@ -# `node_modules/` is already ignored. - -# Do not process fixtures. test diff --git a/.remarkrc b/.remarkrc deleted file mode 100644 index 78a67c30..00000000 --- a/.remarkrc +++ /dev/null @@ -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": "*" - } -} diff --git a/lib/index.js b/lib/index.js index 0bb58a23..85eb6503 100644 --- a/lib/index.js +++ b/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); - - 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; +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. */ + for (id in rules) { + setting = settings[id]; + + known.push(id); + + if (setting != null) { + /* Pass turned on rules `undefined`. */ + if (reset && setting === true) { + setting = undefined; + } + + if (setting === false) { + setting = undefined; + disable.push(id); + } else { + enable.push(id); + } + } - scope.index++; - } + pipeline.use(ruleFactory(id, rules[id], setting)); + } - next(err); - }); - } + /* 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,141 +119,85 @@ 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; - - mapping.push(internals); - length = mapping.length; - - while (++index < length) { - external = mapping[index]; - - if (typeof external === 'string') { - external = loadPlugin(external, { - prefix: 'remark-lint-' - }); - } - - for (ruleId in external) { - rules[ruleId] = external[ruleId]; - } + var index = -1; + var rules = {}; + var external; + var ruleId; + var mapping = externals ? externals.concat() : []; + var length; + + mapping.push(internals); + length = mapping.length; + + while (++index < length) { + external = mapping[index]; + + if (typeof external === 'string') { + external = loadPlugin(external, { + prefix: 'remark-lint-' + }); } - return rules; -} - -/** - * Helper to ensure ruleId’s are dash-cased instead of - * camel-cased. - * - * @param {Object} source - Original settings. - * @return {Object} - Dash-cased settings. - */ -function decamelizeSettings(source) { - var result = {}; - var key; - - for (key in source) { - result[decamelize(key, '-')] = source[key]; + for (ruleId in external) { + rules[ruleId] = external[ruleId]; } + } - return result; + return rules; } /** - * 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. + * Factory to create a plugin from a rule. * * @example - * var processor = lint(remark, { - * 'html': false // Ignore HTML warnings. - * }); + * attachFactory('foo', console.log, false)() // null + * attachFactory('foo', console.log, {})() // plugin * - * @param {Remark} remark - Host object. - * @param {Object?} options - Hash of rule names mapping to - * rule options. + * @param {string} id - Identifier. + * @param {Function} rule - Rule + * @param {*} options - Options for respective rule. + * @return {Function} - Trough ware. */ -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)); +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; } - /* - * Run all rules. - */ + fn(ast, file, options, function (err) { + var messages = file.messages; - remark.use(function () { - return function (node, file, next) { - pipeline.run(node, file, next); - }; - }); + while (scope.index < messages.length) { + messages[scope.index].ruleId = id; + messages[scope.index].source = SOURCE; - /* - * Allow comments to toggle messages. - */ - - remark.use(control, { - 'name': 'lint', - 'source': SOURCE, - 'reset': reset, - 'known': known, - 'enable': enable, - 'disable': disable - }); + scope.index++; + } - /** - * Transformer sort messages. - * - * @param {Node} node - Syntax tree. - * @param {VFile} file - Virtual file. - */ - return function (node, file) { - sort(file); - }; + next(err); + }); + }; } -/* - * Expose. +/** + * Helper to ensure ruleId’s are dash-cased instead of + * camel-cased. + * + * @param {Object} source - Original settings. + * @return {Object} - Dash-cased settings. */ +function decamelizeSettings(source) { + var result = {}; + var key; -module.exports = lint; + for (key in source) { + result[decamelize(key, '-')] = source[key]; + } + + return result; +} diff --git a/lib/rules/blockquote-indentation.js b/lib/rules/blockquote-indentation.js index 24127ec1..63810e85 100644 --- a/lib/rules/blockquote-indentation.js +++ b/lib/rules/blockquote-indentation.js @@ -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 (preferred) { - indent = check(node); - diff = preferred - indent; - word = diff > 0 ? 'Add' : 'Remove'; - - 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); - } - }); + if (position.generated(node) || !node.children.length) { + return; + } - done(); + if (preferred) { + indent = check(node); + diff = preferred - indent; + word = diff > 0 ? 'Add' : 'Remove'; + + 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); + } + }); } -/* - * 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; +} diff --git a/lib/rules/checkbox-character-style.js b/lib/rules/checkbox-character-style.js index 80546e79..24d6bc9a 100644 --- a/lib/rules/checkbox-character-style.js +++ b/lib/rules/checkbox-character-style.js @@ -21,19 +21,19 @@ * @example * * - * + * * - [x] List item * - [x] List item * - * + * * - [X] List item * - [X] List item * - * + * * - [ ] List item * - [ ] List item * - * + * * - [»···] 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); - - if (preferred === 'consistent' || typeof preferred !== 'object') { - preferred = {}; - } - - if (!preferred.unchecked) { - preferred.unchecked = null; - } - - if (!preferred.checked) { - preferred.checked = null; - } - +function checkboxCharacterStyle(ast, file, preferred) { + var contents = file.toString(); + var location = vfileLocation(file); + + if (preferred === 'consistent' || typeof preferred !== 'object') { + preferred = {}; + } + + if (!preferred.unchecked) { + preferred.unchecked = 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\'`' - ); - } - - 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. - */ + type = node.checked ? 'checked' : 'unchecked'; - value = contents.slice(initial, final).trimRight().slice(0, -1); + initial = start(node).offset; + final = (node.children.length ? start(node.children[0]) : end(node)).offset; - /* - * The checkbox character is behind a square - * bracket. - */ + /* For a checkbox to be parsed, it must be followed + * by a white space. */ + value = contents.slice(initial, final).trimRight().slice(0, -1); - character = value.charAt(value.length - 1); - style = preferred[type]; + /* 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; + 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) - } - ); + 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; diff --git a/lib/rules/checkbox-content-indent.js b/lib/rules/checkbox-content-indent.js index ff1a483e..11cdd2e9 100644 --- a/lib/rules/checkbox-content-indent.js +++ b/lib/rules/checkbox-content-indent.js @@ -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); - - visit(ast, 'listItem', function (node) { - var initial; - var final; - var value; - - /* - * Exit early for items without checkbox. - */ - - 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; - - 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); - - 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) - }); +function checkboxContentIndent(ast, file) { + var contents = file.toString(); + var location = vfileLocation(file); + + visit(ast, 'listItem', function (node) { + var initial; + var final; + var value; + + /* Exit early for items without checkbox. */ + 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; + + 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); + + 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) }); - - done(); + }); } - -/* - * Expose. - */ - -module.exports = checkboxContentIndent; diff --git a/lib/rules/code-block-style.js b/lib/rules/code-block-style.js index ed8d6d14..c4efdc60 100644 --- a/lib/rules/code-block-style.js +++ b/lib/rules/code-block-style.js @@ -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; + } - /** - * 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 (position.generated(node)) { - return null; - } - - if ( - node.lang || - /^\s*([~`])\1{2,}/.test(contents.slice(initial, final)) - ) { - return 'fenced'; - } - - return 'indented'; - } + visit(ast, 'code', function (node) { + var current = check(node); - visit(ast, 'code', function (node) { - var current = check(node); + if (!current) { + return; + } - if (!current) { - return; - } + if (!preferred) { + preferred = current; + } else if (preferred !== current) { + file.warn('Code blocks should be ' + preferred, node); + } + }); + + 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 (position.generated(node)) { + return null; + } - if (!preferred) { - preferred = current; - } else if (preferred !== current) { - file.warn('Code blocks should be ' + preferred, node); - } - }); + if ( + node.lang || + /^\s*([~`])\1{2,}/.test(contents.slice(initial, final)) + ) { + return 'fenced'; + } - done(); + return 'indented'; + } } - -/* - * Expose. - */ - -module.exports = codeBlockStyle; diff --git a/lib/rules/definition-case.js b/lib/rules/definition-case.js index 2322a500..ee71ce2d 100644 --- a/lib/rules/definition-case.js +++ b/lib/rules/definition-case.js @@ -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; diff --git a/lib/rules/definition-spacing.js b/lib/rules/definition-spacing.js index 7a4e77b0..b5a6705d 100644 --- a/lib/rules/definition-spacing.js +++ b/lib/rules/definition-spacing.js @@ -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; diff --git a/lib/rules/emphasis-marker.js b/lib/rules/emphasis-marker.js index d98a5d21..d579feca 100644 --- a/lib/rules/emphasis-marker.js +++ b/lib/rules/emphasis-marker.js @@ -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; - - if (MARKERS[preferred] !== true) { - file.fail('Invalid emphasis marker `' + preferred + '`: use either `\'consistent\'`, `\'*\'`, or `\'_\'`'); - done(); - - return; - } +function emphasisMarker(ast, file, preferred) { + preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; - visit(ast, 'emphasis', function (node) { - var marker = file.toString().charAt(position.start(node).offset); + if (MARKERS[preferred] !== true) { + file.fail('Invalid emphasis marker `' + preferred + '`: use either `\'consistent\'`, `\'*\'`, or `\'_\'`'); + return; + } - if (position.generated(node)) { - return; - } + visit(ast, 'emphasis', function (node) { + var marker = file.toString().charAt(position.start(node).offset); - if (preferred) { - if (marker !== preferred) { - file.warn('Emphasis should use `' + preferred + '` as a marker', node); - } - } else { - preferred = marker; - } - }); + if (position.generated(node)) { + return; + } - done(); + if (preferred) { + if (marker !== preferred) { + file.warn('Emphasis should use `' + preferred + '` as a marker', node); + } + } else { + preferred = marker; + } + }); } - -/* - * Expose. - */ - -module.exports = emphasisMarker; diff --git a/lib/rules/fenced-code-flag.js b/lib/rules/fenced-code-flag.js index afaf98e0..1535439d 100644 --- a/lib/rules/fenced-code-flag.js +++ b/lib/rules/fenced-code-flag.js @@ -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.} [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 = []; - - if (typeof preferred === 'object' && !('length' in preferred)) { - allowEmpty = Boolean(preferred.allowEmpty); +function fencedCodeFlag(ast, file, preferred) { + var contents = file.toString(); + var allowEmpty = false; + var flags = []; - preferred = preferred.flags; - } + if (typeof preferred === 'object' && !('length' in preferred)) { + allowEmpty = Boolean(preferred.allowEmpty); - if (typeof preferred === 'object' && 'length' in preferred) { - flags = String(preferred).split(','); - } + preferred = preferred.flags; + } - visit(ast, 'code', function (node) { - var value = contents.slice(start(node).offset, end(node).offset); + if (typeof preferred === 'object' && 'length' in preferred) { + flags = String(preferred).split(','); + } - if (position.generated(node)) { - return; - } + visit(ast, 'code', function (node) { + var value = contents.slice(start(node).offset, end(node).offset); - 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); - } - }); + if (position.generated(node)) { + return; + } - done(); + 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); + } + }); } - -/* - * Expose. - */ - -module.exports = fencedCodeFlag; diff --git a/lib/rules/fenced-code-marker.js b/lib/rules/fenced-code-marker.js index 12bcbf06..9ffadacb 100644 --- a/lib/rules/fenced-code-marker.js +++ b/lib/rules/fenced-code-marker.js @@ -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(); - - preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; - - if (MARKERS[preferred] !== true) { - file.fail('Invalid fenced code marker `' + preferred + '`: use either `\'consistent\'`, `` \'\`\' ``, or `\'~\'`'); - done(); - - return; - } +function fencedCodeMarker(ast, file, preferred) { + var contents = file.toString(); - visit(ast, 'code', function (node) { - var marker = contents.substr(position.start(node).offset, 4); + preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; - if (position.generated(node)) { - return; - } + if (MARKERS[preferred] !== true) { + file.fail('Invalid fenced code marker `' + preferred + '`: use either `\'consistent\'`, `` \'`\' ``, or `\'~\'`'); + return; + } - marker = marker.trimLeft().charAt(0); + visit(ast, 'code', function (node) { + var marker = contents.substr(position.start(node).offset, 4); - /* - * Ignore unfenced code blocks. - */ + if (position.generated(node)) { + return; + } - if (MARKERS[marker] !== true) { - return; - } + marker = marker.trimLeft().charAt(0); - if (preferred) { - if (marker !== preferred) { - file.warn('Fenced code should use ' + preferred + ' as a marker', node); - } - } else { - preferred = marker; - } - }); + /* Ignore unfenced code blocks. */ + if (MARKERS[marker] !== true) { + return; + } - done(); + if (preferred) { + if (marker !== preferred) { + file.warn('Fenced code should use ' + preferred + ' as a marker', node); + } + } else { + preferred = marker; + } + }); } - -/* - * Expose. - */ - -module.exports = fencedCodeMarker; diff --git a/lib/rules/file-extension.js b/lib/rules/file-extension.js index 8290744f..17fd7065 100644 --- a/lib/rules/file-extension.js +++ b/lib/rules/file-extension.js @@ -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; - - preferred = typeof preferred === 'string' ? preferred : 'md'; +function fileExtension(ast, file, preferred) { + var ext = file.extension; - if (ext !== '' && ext !== preferred) { - file.warn('Invalid extension: use `' + preferred + '`'); - } + preferred = typeof preferred === 'string' ? preferred : 'md'; - done(); + if (ext !== '' && ext !== preferred) { + file.warn('Invalid extension: use `' + preferred + '`'); + } } - -/* - * Expose. - */ - -module.exports = fileExtension; diff --git a/lib/rules/final-definition.js b/lib/rules/final-definition.js index 24c406fe..2d568216 100644 --- a/lib/rules/final-definition.js +++ b/lib/rules/final-definition.js @@ -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; - - visit(ast, function (node) { - var line = start(node).line; - - /* - * Ignore generated nodes. - */ - - 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(); +function finalDefinition(ast, file) { + var last = null; + + visit(ast, function (node) { + var line = start(node).line; + + /* Ignore generated nodes. */ + 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); } - -/* - * Expose. - */ - -module.exports = finalDefinition; diff --git a/lib/rules/final-newline.js b/lib/rules/final-newline.js index e510c588..641e8aed 100644 --- a/lib/rules/final-newline.js +++ b/lib/rules/final-newline.js @@ -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; - - if (last > 0 && contents.charAt(last) !== '\n') { - file.warn('Missing newline character at end of file'); - } +function finalNewline(ast, file) { + var contents = file.toString(); + var last = contents.length - 1; - done(); + if (last > 0 && contents.charAt(last) !== '\n') { + file.warn('Missing newline character at end of file'); + } } - -/* - * Expose. - */ - -module.exports = finalNewline; diff --git a/lib/rules/first-heading-level.js b/lib/rules/first-heading-level.js index de214069..e001fd33 100644 --- a/lib/rules/first-heading-level.js +++ b/lib/rules/first-heading-level.js @@ -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; - - visit(ast, 'heading', function (node) { - if (position.generated(node)) { - return null; - } +function firstHeadingLevel(ast, file, preferred) { + var style = preferred && preferred !== true ? preferred : 1; - if (node.depth !== style) { - file.warn('First heading level should be `' + style + '`', node); - } + visit(ast, 'heading', function (node) { + if (position.generated(node)) { + return; + } - return false; - }); + if (node.depth !== style) { + file.warn('First heading level should be `' + style + '`', node); + } - done(); + return false; + }); } - -module.exports = firstHeadingLevel; diff --git a/lib/rules/hard-break-spaces.js b/lib/rules/hard-break-spaces.js index 64347936..8be63ccd 100644 --- a/lib/rules/hard-break-spaces.js +++ b/lib/rules/hard-break-spaces.js @@ -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(); - - visit(ast, 'break', function (node) { - var start = position.start(node).offset; - var end = position.end(node).offset; - var value; +function hardBreakSpaces(ast, file) { + var contents = file.toString(); - if (position.generated(node)) { - return; - } + visit(ast, 'break', function (node) { + var start = position.start(node).offset; + var end = position.end(node).offset; + var value; - value = contents.slice(start, end).split('\n', 1)[0].replace(/\r$/, ''); + if (position.generated(node)) { + return; + } - if (value.length > 2) { - file.warn('Use two spaces for hard line breaks', node); - } - }); + value = contents.slice(start, end).split('\n', 1)[0].replace(/\r$/, ''); - done(); + if (value.length > 2) { + file.warn('Use two spaces for hard line breaks', node); + } + }); } - -/* - * Expose. - */ - -module.exports = hardBreakSpaces; diff --git a/lib/rules/heading-increment.js b/lib/rules/heading-increment.js index 6371d21a..3e4abe93 100644 --- a/lib/rules/heading-increment.js +++ b/lib/rules/heading-increment.js @@ -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; diff --git a/lib/rules/heading-style.js b/lib/rules/heading-style.js index 7786468f..30e2ff39 100644 --- a/lib/rules/heading-style.js +++ b/lib/rules/heading-style.js @@ -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; - - visit(ast, 'heading', function (node) { - if (position.generated(node)) { - return; - } +function headingStyle(ast, file, preferred) { + preferred = TYPES.indexOf(preferred) === -1 ? null : preferred; - if (preferred) { - if (style(node, preferred) !== preferred) { - file.warn('Headings should use ' + preferred, node); - } - } else { - preferred = style(node, preferred); - } - }); + visit(ast, 'heading', function (node) { + if (position.generated(node)) { + return; + } - done(); + if (preferred) { + if (style(node, preferred) !== preferred) { + file.warn('Headings should use ' + preferred, node); + } + } else { + preferred = style(node, preferred); + } + }); } - -/* - * Expose. - */ - -module.exports = headingStyle; diff --git a/lib/rules/index.js b/lib/rules/index.js index 2685c0c0..c6365ee5 100644 --- a/lib/rules/index.js +++ b/lib/rules/index.js @@ -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') }; diff --git a/lib/rules/link-title-style.js b/lib/rules/link-title-style.js index b822d1c4..fe3ef063 100644 --- a/lib/rules/link-title-style.js +++ b/lib/rules/link-title-style.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. - */ +/* Expose. */ +module.exports = linkTitleStyle; +/* Methods. */ +var end = position.end; + +/* Map of valid markers. */ var MARKERS = { - '"': true, - '\'': true, - ')': true, - 'null': true + '"': true, + '\'': true, + ')': true, + 'null': true }; -/* - * Methods. - */ - -var end = position.end; - /** * 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); - - preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; +function linkTitleStyle(ast, file, preferred) { + var contents = file.toString(); + var location = vfileLocation(file); + + preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : 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 (preferred === '()' || preferred === '(') { - preferred = ')'; + if (node.type !== 'definition') { + last--; } - if (MARKERS[preferred] !== true) { - file.fail('Invalid link title style marker `' + preferred + '`: use either `\'consistent\'`, `\'"\'`, `\'\\\'\'`, or `\'()\'`'); - done(); + while (last) { + character = contents.charAt(last); - return; + if (/\s/.test(character)) { + last--; + } else { + break; + } } - /** - * 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 (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); - } + /* Not a title. */ + if (!(character in MARKERS)) { + return; } - visit(ast, 'link', validate); - visit(ast, 'image', validate); - visit(ast, 'definition', validate); - - 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; diff --git a/lib/rules/list-item-bullet-indent.js b/lib/rules/list-item-bullet-indent.js index fcb8db53..797d3e8d 100644 --- a/lib/rules/list-item-bullet-indent.js +++ b/lib/rules/list-item-bullet-indent.js @@ -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; diff --git a/lib/rules/list-item-content-indent.js b/lib/rules/list-item-content-indent.js index 67efec8a..2721b9e3 100644 --- a/lib/rules/list-item-content-indent.js +++ b/lib/rules/list-item-content-indent.js @@ -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(); - - 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; - - 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. - */ - - 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; - - while (contents.charAt(char) !== '[') { - char--; - } - - column -= begin.offset - char; - } - - style = column; - - return; - } - - /* - * 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 - } - ); - } - }); +function listItemContentIndent(ast, file) { + var contents = file.toString(); + + 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; + + 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. */ + 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; + + while (contents.charAt(char) !== '[') { + char--; + } + + column -= begin.offset - char; + } + + style = column; + + return; + } + + /* 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 + } + ); + } }); - - done(); + }); } - -/* - * Expose. - */ - -module.exports = listItemContentIndent; diff --git a/lib/rules/list-item-indent.js b/lib/rules/list-item-indent.js index 043e3e6d..ec94cb2c 100644 --- a/lib/rules/list-item-indent.js +++ b/lib/rules/list-item-indent.js @@ -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; - - if (position.generated(node)) { - return; - } - - 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; - - marker = contents.slice(initial, final); - - /* - * Support checkboxes. - */ - - marker = marker.replace(/\[[x ]?\]\s*$/i, ''); - - bulletSize = marker.trimRight().length; - tab = Math.ceil(bulletSize / 4) * 4; - - 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) - ); - } - }); + 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; + + marker = contents.slice(initial, final); + + /* Support checkboxes. */ + marker = marker.replace(/\[[x ]?\]\s*$/i, ''); + + bulletSize = marker.trimRight().length; + tab = Math.ceil(bulletSize / 4) * 4; + + 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) + ); + } }); - - done(); + }); } - -/* - * Expose. - */ - -module.exports = listItemIndent; diff --git a/lib/rules/list-item-spacing.js b/lib/rules/list-item-spacing.js index 08c954e6..3734534b 100644 --- a/lib/rules/list-item-spacing.js +++ b/lib/rules/list-item-spacing.js @@ -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; + } + + 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; + } + }); - if (position.generated(node)) { - return; + 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) + }); } - - 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) - }); - } - } - }); + } }); - - done(); + }); } - -/* - * Expose. - */ - -module.exports = listItemSpacing; diff --git a/lib/rules/maximum-heading-length.js b/lib/rules/maximum-heading-length.js index f71999de..65776c49 100644 --- a/lib/rules/maximum-heading-length.js +++ b/lib/rules/maximum-heading-length.js @@ -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; - - visit(ast, 'heading', function (node) { - if (position.generated(node)) { - return; - } - - if (toString(node).length > preferred) { - file.warn('Use headings shorter than `' + preferred + '`', node); - } - }); - - done(); +function maximumHeadingLength(ast, file, preferred) { + preferred = isNaN(preferred) || typeof preferred !== 'number' ? 60 : preferred; + + visit(ast, 'heading', function (node) { + if (position.generated(node)) { + return; + } + + if (toString(node).length > preferred) { + file.warn('Use headings shorter than `' + preferred + '`', node); + } + }); } - -/* - * Expose. - */ - -module.exports = maximumHeadingLength; diff --git a/lib/rules/maximum-line-length.js b/lib/rules/maximum-line-length.js index ad54b0b6..21173cdd 100644 --- a/lib/rules/maximum-line-length.js +++ b/lib/rules/maximum-line-length.js @@ -32,37 +32,17 @@ '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; -/** - * Check if `node` is applicable, as in, if it should be - * ignored. - * - * @param {Node} node - Node to test. - * @return {boolean} - Whether or not `node` should be - * ignored. - */ -function isIgnored(node) { - 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, @@ -71,118 +51,111 @@ function isIgnored(node) { * @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] = ''; - } +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; } - /* - * 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); + 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 + }); } + } - visit(ast, 'link', validateLink); - visit(ast, 'image', validateLink); + return; - /* - * Iterate over every line, and warn for - * violating lines. - */ + /** + * Whitelist from `initial` to `final`, zero-based. + * + * @param {number} initial - Start. + * @param {number} final - End. + */ + function whitelist(initial, final) { + initial--; - while (++index < length) { - lineLength = matrix[index].length; + 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; + } - if (lineLength > style) { - file.warn('Line must be at most ' + style + ' characters', { - 'line': index + 1, - 'column': lineLength + 1 - }); - } + /* No whitelisting when starting after the border, + * or ending before it. */ + if (initial.column > style || final.column < style) { + return; } - done(); + /* 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); + } } -/* - * Expose. +/** + * Check if `node` is applicable, as in, if it should be + * ignored. + * + * @param {Node} node - Node to test. + * @return {boolean} - Whether or not `node` should be + * ignored. */ - -module.exports = maximumLineLength; +function isIgnored(node) { + return node.type === 'heading' || + node.type === 'table' || + node.type === 'code' || + node.type === 'definition'; +} diff --git a/lib/rules/no-auto-link-without-protocol.js b/lib/rules/no-auto-link-without-protocol.js index 4144f9e5..d2623103 100644 --- a/lib/rules/no-auto-link-without-protocol.js +++ b/lib/rules/no-auto-link-without-protocol.js @@ -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,45 +40,35 @@ var end = position.end; var PROTOCOL = /^[a-z][a-z+.-]+:\/?/i; -/** - * Assert `node`s reference starts with a protocol. - * - * @param {Node} node - Node to test. - * @return {boolean} - Whether `node` has a protocol. - */ -function hasProtocol(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; - } +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 (initial === head - 1 && final === tail + 1 && !hasProtocol(node)) { - file.warn('All automatic links must start with a protocol', node); - } - }); + if (position.generated(node)) { + return; + } - done(); + if (initial === head - 1 && final === tail + 1 && !hasProtocol(node)) { + file.warn('All automatic links must start with a protocol', node); + } + }); } -/* - * Expose. +/** + * Assert `node`s reference starts with a protocol. + * + * @param {Node} node - Node to test. + * @return {boolean} - Whether `node` has a protocol. */ - -module.exports = noAutoLinkWithoutProtocol; +function hasProtocol(node) { + return PROTOCOL.test(toString(node)); +} diff --git a/lib/rules/no-blockquote-without-caret.js b/lib/rules/no-blockquote-without-caret.js index d16b937c..343bcc7d 100644 --- a/lib/rules/no-blockquote-without-caret.js +++ b/lib/rules/no-blockquote-without-caret.js @@ -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; + 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); + while (++offset < last) { + character = contents.charAt(offset); - if (character === '>') { - return; - } + if (character === '>') { + return; + } - /* istanbul ignore else - just for safety */ - if (character !== ' ' && character !== '\t') { - break; - } - } + /* 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; diff --git a/lib/rules/no-consecutive-blank-lines.js b/lib/rules/no-consecutive-blank-lines.js index 352d5ed4..4511da95 100644 --- a/lib/rules/no-consecutive-blank-lines.js +++ b/lib/rules/no-consecutive-blank-lines.js @@ -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'; - - diff = Math.abs(diff) - max; - - if (diff > 0) { - file.warn('Remove ' + diff + ' ' + plural('line', diff) + ' ' + word + ' node', end); - } +function noConsecutiveBlankLines(ast, file) { + visit(ast, function (node) { + var children = node.children; + var head = children && children[0]; + var tail = children && children[children.length - 1]; + + 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 (position.generated(node)) { - 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 (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); + }); -/* - * Expose. - */ - -module.exports = noConsecutiveBlankLines; + /* 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); + } + } +} diff --git a/lib/rules/no-duplicate-definitions.js b/lib/rules/no-duplicate-definitions.js index e625f5ef..ba333de1 100644 --- a/lib/rules/no-duplicate-definitions.js +++ b/lib/rules/no-duplicate-definitions.js @@ -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 = {}; - - /** - * Check `node`. - * - * @param {Node} node - Node. - */ - function validate(node) { - var duplicate = map[node.identifier]; - var pos; +function noDuplicateDefinitions(ast, file) { + var map = {}; - if (position.generated(node)) { - return; - } + visit(ast, 'definition', validate); + visit(ast, 'footnoteDefinition', validate); - if (duplicate && duplicate.type) { - pos = position.start(duplicate); + return; - file.warn( - 'Do not use definitions with the same identifier (' + - pos.line + ':' + pos.column + ')', - node - ); - } + /** + * Check `node`. + * + * @param {Node} node - Node. + */ + function validate(node) { + var duplicate = map[node.identifier]; + var pos; - 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(); -} - -/* - * Expose. - */ + file.warn( + 'Do not use definitions with the same identifier (' + + pos.line + ':' + pos.column + ')', + node + ); + } -module.exports = noDuplicateDefinitions; + map[node.identifier] = node; + } +} diff --git a/lib/rules/no-duplicate-headings.js b/lib/rules/no-duplicate-headings.js index f6d1afb3..6c814f74 100644 --- a/lib/rules/no-duplicate-headings.js +++ b/lib/rules/no-duplicate-headings.js @@ -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 = {}; - - visit(ast, 'heading', function (node) { - var value = toString(node).toUpperCase(); - var duplicate = map[value]; - var pos; +function noDuplicateHeadings(ast, file) { + var map = {}; - if (position.generated(node)) { - return; - } + visit(ast, 'heading', function (node) { + var value = toString(node).toUpperCase(); + var duplicate = map[value]; + var pos; - if (duplicate && duplicate.type === 'heading') { - pos = position.start(duplicate); + if (position.generated(node)) { + return; + } - file.warn( - 'Do not use headings with similar content (' + - pos.line + ':' + pos.column + ')', - node - ); - } + if (duplicate && duplicate.type === 'heading') { + pos = position.start(duplicate); - map[value] = node; - }); + file.warn( + 'Do not use headings with similar content (' + + pos.line + ':' + pos.column + ')', + node + ); + } - done(); + map[value] = node; + }); } - -/* - * Expose. - */ - -module.exports = noDuplicateHeadings; diff --git a/lib/rules/no-emphasis-as-heading.js b/lib/rules/no-emphasis-as-heading.js index aecd353d..8964cc40 100644 --- a/lib/rules/no-emphasis-as-heading.js +++ b/lib/rules/no-emphasis-as-heading.js @@ -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]; - - 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(); +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 ( + (!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; diff --git a/lib/rules/no-file-name-articles.js b/lib/rules/no-file-name-articles.js index 50a6a9db..ee77432a 100644 --- a/lib/rules/no-file-name-articles.js +++ b/lib/rules/no-file-name-articles.js @@ -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); - - if (match) { - file.warn('Do not start file names with `' + match[0] + '`'); - } +function noFileNameArticles(ast, file) { + var match = file.filename && file.filename.match(/^(the|an?)\b/i); - done(); + if (match) { + file.warn('Do not start file names with `' + match[0] + '`'); + } } - -/* - * Expose. - */ - -module.exports = noFileNameArticles; diff --git a/lib/rules/no-file-name-consecutive-dashes.js b/lib/rules/no-file-name-consecutive-dashes.js index 616c0881..2a99d15d 100644 --- a/lib/rules/no-file-name-consecutive-dashes.js +++ b/lib/rules/no-file-name-consecutive-dashes.js @@ -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; diff --git a/lib/rules/no-file-name-irregular-characters.js b/lib/rules/no-file-name-irregular-characters.js index cebfad28..2582a032 100644 --- a/lib/rules/no-file-name-irregular-characters.js +++ b/lib/rules/no-file-name-irregular-characters.js @@ -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; - - if (typeof expression === 'string') { - expression = new RegExp('[^' + expression + ']'); - } +function noFileNameIrregularCharacters(ast, file, preferred) { + var expression = preferred || /[^\\.a-zA-Z0-9-]/; + var match; - match = file.filename && file.filename.match(expression); + if (typeof expression === 'string') { + expression = new RegExp('[^' + expression + ']'); + } - if (match) { - file.warn('Do not use `' + match[0] + '` in a file name'); - } + match = file.filename && file.filename.match(expression); - done(); + if (match) { + file.warn('Do not use `' + match[0] + '` in a file name'); + } } - -/* - * Expose. - */ - -module.exports = noFileNameIrregularCharacters; diff --git a/lib/rules/no-file-name-mixed-case.js b/lib/rules/no-file-name-mixed-case.js index 2a34bf66..a311bd4a 100644 --- a/lib/rules/no-file-name-mixed-case.js +++ b/lib/rules/no-file-name-mixed-case.js @@ -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; - - if (name && !(name === name.toLowerCase() || name === name.toUpperCase())) { - file.warn('Do not mix casing in file names'); - } +function noFileNameMixedCase(ast, file) { + var name = file.filename; - done(); + if (name && !(name === name.toLowerCase() || name === name.toUpperCase())) { + file.warn('Do not mix casing in file names'); + } } - -/* - * Expose. - */ - -module.exports = noFileNameMixedCase; diff --git a/lib/rules/no-file-name-outer-dashes.js b/lib/rules/no-file-name-outer-dashes.js index f279b43e..c2a9bcf7 100644 --- a/lib/rules/no-file-name-outer-dashes.js +++ b/lib/rules/no-file-name-outer-dashes.js @@ -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; diff --git a/lib/rules/no-heading-content-indent.js b/lib/rules/no-heading-content-indent.js index b0a99fe4..11575cce 100644 --- a/lib/rules/no-heading-content-indent.js +++ b/lib/rules/no-heading-content-indent.js @@ -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(); - - 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 (type === 'atx' || type === 'atx-closed') { - initial = start(node); - index = initial.offset; - char = contents.charAt(index); - - while (char && char !== '#') { - index++; - char = contents.charAt(index); - } - - /* CR/LF bug: wooorm/remark#195. */ - if (!char) { - return; - } - - index = depth + (index - initial.offset); - head = start(children[0]).column; - - /* - * Ignore empty headings. - */ - - if (!head) { - return; - } - - diff = head - initial.column - 1 - index; - - 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]) - ); - } - } - - /* - * 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 (diff) { - file.warn( - 'Remove ' + diff + ' ' + plural('space', diff) + - ' after this heading’s content', - final - ); - } - } - }); - - done(); +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; + + if (position.generated(node)) { + return; + } + + if (type === 'atx' || type === 'atx-closed') { + initial = start(node); + index = initial.offset; + char = contents.charAt(index); + + while (char && char !== '#') { + index++; + char = contents.charAt(index); + } + + /* CR/LF bug: wooorm/remark#195. */ + if (!char) { + return; + } + + index = depth + (index - initial.offset); + head = start(children[0]).column; + + /* + * Ignore empty headings. + */ + + if (!head) { + return; + } + + diff = head - initial.column - 1 - index; + + 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]) + ); + } + } + + /* + * 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 (diff) { + file.warn( + 'Remove ' + diff + ' ' + plural('space', diff) + + ' after this heading’s content', + final + ); + } + } + }); } - -/* - * Expose. - */ - -module.exports = noHeadingContentIndent; diff --git a/lib/rules/no-heading-indent.js b/lib/rules/no-heading-indent.js index 2fa3f618..73e6c4ea 100644 --- a/lib/rules/no-heading-indent.js +++ b/lib/rules/no-heading-indent.js @@ -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; - - 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; - } - - while (++index < length) { - character = contents.charAt(index); - - if (character !== ' ' && character !== '\t') { - break; - } +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; + + 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 } - - 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; diff --git a/lib/rules/no-heading-punctuation.js b/lib/rules/no-heading-punctuation.js index 146e5377..c54676a8 100644 --- a/lib/rules/no-heading-punctuation.js +++ b/lib/rules/no-heading-punctuation.js @@ -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; diff --git a/lib/rules/no-html.js b/lib/rules/no-html.js index b3cb4589..577423fd 100644 --- a/lib/rules/no-html.js +++ b/lib/rules/no-html.js @@ -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*