From 6c1b4cf6b01b5e1ea63ca05f986b17dd03d010bf Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Fri, 18 May 2018 12:30:21 +0200 Subject: [PATCH] Refactor code-style --- .prettierignore | 3 + .remarkrc.js | 4 +- package.json | 27 +- .../index.js | 69 +-- .../index.js | 143 +++--- .../index.js | 62 +-- .../remark-lint-code-block-style/index.js | 73 ++- packages/remark-lint-definition-case/index.js | 38 +- .../remark-lint-definition-spacing/index.js | 40 +- packages/remark-lint-emphasis-marker/index.js | 52 +- .../remark-lint-fenced-code-flag/index.js | 59 ++- .../remark-lint-fenced-code-marker/index.js | 66 +-- packages/remark-lint-file-extension/index.js | 20 +- .../remark-lint-final-definition/index.js | 33 +- packages/remark-lint-final-newline/index.js | 14 +- .../remark-lint-first-heading-level/index.js | 48 +- .../remark-lint-hard-break-spaces/index.js | 39 +- .../remark-lint-heading-increment/index.js | 34 +- packages/remark-lint-heading-style/index.js | 36 +- packages/remark-lint-linebreak-style/index.js | 61 +-- .../remark-lint-link-title-style/index.js | 88 ++-- .../index.js | 62 +-- .../index.js | 87 ++-- .../remark-lint-list-item-indent/index.js | 116 ++--- .../remark-lint-list-item-spacing/index.js | 141 +++--- .../index.js | 29 +- .../remark-lint-maximum-line-length/index.js | 110 ++-- .../index.js | 48 +- .../index.js | 68 +-- .../index.js | 108 ++-- .../readme.md | 11 +- .../index.js | 49 +- .../index.js | 47 +- .../index.js | 49 +- .../index.js | 34 +- packages/remark-lint-no-empty-url/index.js | 20 +- .../index.js | 12 +- .../index.js | 15 +- .../index.js | 25 +- .../index.js | 17 +- .../index.js | 15 +- .../index.js | 111 ++-- .../remark-lint-no-heading-indent/index.js | 51 +- .../index.js | 39 +- .../index.js | 40 +- packages/remark-lint-no-html/index.js | 18 +- .../remark-lint-no-inline-padding/index.js | 40 +- packages/remark-lint-no-literal-urls/index.js | 45 +- .../index.js | 71 ++- .../index.js | 45 +- .../index.js | 90 ++-- .../index.js | 37 +- .../remark-lint-no-shell-dollars/index.js | 58 ++- .../remark-lint-no-shell-dollars/readme.md | 5 + .../index.js | 27 +- .../index.js | 27 +- .../remark-lint-no-table-indentation/index.js | 41 +- packages/remark-lint-no-tabs/index.js | 26 +- .../index.js | 29 +- .../index.js | 48 +- .../index.js | 86 ++-- .../index.js | 104 ++-- .../readme.md | 17 + packages/remark-lint-rule-style/index.js | 58 +-- packages/remark-lint-strong-marker/index.js | 52 +- .../remark-lint-table-cell-padding/index.js | 331 +++++++----- .../remark-lint-table-cell-padding/readme.md | 139 ++++- .../remark-lint-table-pipe-alignment/index.js | 105 ++-- packages/remark-lint-table-pipes/index.js | 65 ++- .../index.js | 86 ++-- packages/remark-lint/index.js | 10 +- .../remark-preset-lint-consistent/index.js | 4 +- .../index.js | 4 +- .../remark-preset-lint-recommended/index.js | 4 +- packages/unified-lint-rule/index.js | 102 ++-- script/build-presets.js | 156 +++--- script/build-rules.js | 276 +++++----- script/characters.js | 4 +- script/plugin/list-of-presets.js | 35 +- script/plugin/list-of-rules.js | 34 +- script/util/find.js | 30 +- script/util/presets.js | 10 +- script/util/rule.js | 116 +++-- script/util/rules.js | 10 +- test.js | 476 +++++++++--------- 85 files changed, 2791 insertions(+), 2443 deletions(-) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..7a7d04d7 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +coverage/ +remark-lint.js +remark-lint.min.js diff --git a/.remarkrc.js b/.remarkrc.js index 2ecb0645..b65e70c2 100644 --- a/.remarkrc.js +++ b/.remarkrc.js @@ -1,4 +1,4 @@ -exports.settings = {bullet: '*', paddedTable: false}; +exports.settings = {bullet: '*', paddedTable: false} exports.plugins = [ require('./packages/remark-preset-lint-recommended'), @@ -9,4 +9,4 @@ exports.plugins = [ require('remark-validate-links'), require('./script/plugin/list-of-presets'), require('./script/plugin/list-of-rules') -]; +] diff --git a/package.json b/package.json index c8aae224..9563af32 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "mdast-zone": "^3.0.0", "nyc": "^11.0.0", "parse-author": "^2.0.0", + "prettier": "^1.12.1", "remark": "^9.0.0", "remark-cli": "^5.0.0", "remark-comment-config": "^5.0.0", @@ -55,16 +56,16 @@ }, "scripts": { "prepublish": "lerna bootstrap", - "build-presets": "node script/build-presets", - "build-rules": "node script/build-rules", - "build-md": "remark . -qfo", - "build-bundle": "browserify packages/remark-lint/index.js --bare -s remarkLint > remark-lint.js", - "build-mangle": "esmangle remark-lint.js > remark-lint.min.js", - "build": "npm run build-presets && npm run build-rules && npm run build-md && npm run build-bundle && npm run build-mangle", - "lint": "xo", + "format": "remark . -qfo && prettier --write '**/*.js' && xo --fix", + "generate:presets": "node script/build-presets", + "generate:rules": "node script/build-rules", + "generate": "npm run generate:presets && npm run generate:rules", + "build:bundle": "browserify packages/remark-lint/index.js --bare -s remarkLint > remark-lint.js", + "build:mangle": "esmangle remark-lint.js > remark-lint.min.js", + "build": "npm run build:bundle && npm run build:mangle", "test-api": "node test", "test-coverage": "nyc --reporter lcov tape test.js", - "test": "npm run build && npm run lint && npm run test-coverage" + "test": "npm run generate && npm run format && npm run build && npm run test-coverage" }, "nyc": { "check-coverage": true, @@ -72,8 +73,16 @@ "functions": 100, "branches": 100 }, + "prettier": { + "tabWidth": 2, + "useTabs": false, + "singleQuote": true, + "bracketSpacing": false, + "semi": false, + "trailingComma": "none" + }, "xo": { - "space": true, + "prettier": true, "esnext": false, "rules": { "guard-for-in": "off", diff --git a/packages/remark-lint-blockquote-indentation/index.js b/packages/remark-lint-blockquote-indentation/index.js index a13cd509..9ddd50ee 100644 --- a/packages/remark-lint-blockquote-indentation/index.js +++ b/packages/remark-lint-blockquote-indentation/index.js @@ -45,59 +45,64 @@ * 9:3: Add 1 space between blockquote and content */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var plural = require('plur'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); -var toString = require('mdast-util-to-string'); +var rule = require('unified-lint-rule') +var plural = require('plur') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') +var toString = require('mdast-util-to-string') -module.exports = rule('remark-lint:blockquote-indentation', blockquoteIndentation); +module.exports = rule( + 'remark-lint:blockquote-indentation', + blockquoteIndentation +) -function blockquoteIndentation(tree, file, preferred) { - preferred = isNaN(preferred) || typeof preferred !== 'number' ? null : preferred; +function blockquoteIndentation(tree, file, pref) { + pref = typeof pref === 'number' && !isNaN(pref) ? pref : null - visit(tree, 'blockquote', visitor); + visit(tree, 'blockquote', visitor) function visitor(node) { - var indent; - var diff; - var word; + var diff + var diffAbs + var reason if (generated(node) || node.children.length === 0) { - return; + return } - if (preferred) { - indent = check(node); - diff = preferred - indent; - word = diff > 0 ? 'Add' : 'Remove'; - - diff = Math.abs(diff); + if (pref) { + diff = pref - check(node) if (diff !== 0) { - file.message( - word + ' ' + diff + ' ' + plural('space', diff) + - ' between blockquote and content', - position.start(node.children[0]) - ); + diffAbs = Math.abs(diff) + + reason = + (diff > 0 ? 'Add' : 'Remove') + + ' ' + + diffAbs + + ' ' + + plural('space', diffAbs) + + ' between blockquote and content' + + file.message(reason, position.start(node.children[0])) } } else { - preferred = check(node); + pref = check(node) } } } function check(node) { - var head = node.children[0]; - var indentation = position.start(head).column - position.start(node).column; - var padding = toString(head).match(/^ +/); + 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; + indentation += padding[0].length } - return indentation; + return indentation } diff --git a/packages/remark-lint-checkbox-character-style/index.js b/packages/remark-lint-checkbox-character-style/index.js index d4cb35af..285ed093 100644 --- a/packages/remark-lint-checkbox-character-style/index.js +++ b/packages/remark-lint-checkbox-character-style/index.js @@ -68,103 +68,94 @@ * 1:1: Invalid checked checkbox marker `!`: use either `'x'`, or `'X'` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var vfileLocation = require('vfile-location'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var vfileLocation = require('vfile-location') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:checkbox-character-style', checkboxCharacterStyle); +module.exports = rule( + 'remark-lint:checkbox-character-style', + checkboxCharacterStyle +) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end -var CHECKED = {x: true, X: true}; -var UNCHECKED = {' ': true, '\t': true}; +var checked = {x: true, X: true} +var unchecked = {' ': true, '\t': true} +var types = {true: 'checked', false: 'unchecked'} -function checkboxCharacterStyle(tree, file, preferred) { - var contents = file.toString(); - var location = vfileLocation(file); +function checkboxCharacterStyle(tree, file, pref) { + var contents = String(file) + var location = vfileLocation(file) - if (preferred === 'consistent' || typeof preferred !== 'object') { - preferred = {}; - } - - if (!preferred.unchecked) { - preferred.unchecked = null; - } - - if (!preferred.checked) { - preferred.checked = null; - } + pref = typeof pref === 'object' ? pref : {} - if ( - preferred.unchecked !== null && - UNCHECKED[preferred.unchecked] !== true - ) { + if (pref.unchecked && unchecked[pref.unchecked] !== true) { file.fail( 'Invalid unchecked checkbox marker `' + - preferred.unchecked + - '`: use either `\'\\t\'`, or `\' \'`' - ); + pref.unchecked + + "`: use either `'\\t'`, or `' '`" + ) } - if ( - preferred.checked !== null && - CHECKED[preferred.checked] !== true - ) { + if (pref.checked && checked[pref.checked] !== true) { file.fail( 'Invalid checked checkbox marker `' + - preferred.checked + - '`: use either `\'x\'`, or `\'X\'`' - ); + pref.checked + + "`: use either `'x'`, or `'X'`" + ) } - visit(tree, 'listItem', visitor); + visit(tree, 'listItem', visitor) function visitor(node) { - var type; - var initial; - var final; - var stop; - var value; - var style; - var character; + var type + var initial + var final + var value + var style + var character + var reason /* Exit early for items without checkbox. */ - if (node.checked !== Boolean(node.checked) || generated(node)) { - return; + if (typeof node.checked !== 'boolean' || generated(node)) { + return } - type = node.checked ? 'checked' : 'unchecked'; - - initial = start(node).offset; - final = (node.children.length ? start(node.children[0]) : end(node)).offset; - - /* For a checkbox to be parsed, it must be followed - * by a white space. */ - value = contents.slice(initial, final).trimRight().slice(0, -1); - - /* The checkbox character is behind a square - * bracket. */ - character = value.charAt(value.length - 1); - style = preferred[type]; - - if (style === null) { - preferred[type] = character; - } else if (character !== style) { - stop = initial + value.length; - - file.message( - type.charAt(0).toUpperCase() + type.slice(1) + - ' checkboxes should use `' + style + '` as a marker', - { - start: location.toPosition(stop - 1), - end: location.toPosition(stop) - } - ); + type = types[node.checked] + initial = start(node).offset + final = (node.children.length ? start(node.children[0]) : end(node)).offset + + /* For a checkbox to be parsed, it must be followed by a white space. */ + value = contents + .slice(initial, final) + .trimRight() + .slice(0, -1) + + /* The checkbox character is behind a square bracket. */ + character = value.charAt(value.length - 1) + style = pref[type] + + if (style) { + if (character !== style) { + reason = + type.charAt(0).toUpperCase() + + type.slice(1) + + ' checkboxes should use `' + + style + + '` as a marker' + + file.message(reason, { + start: location.toPosition(initial + value.length - 1), + end: location.toPosition(initial + value.length) + }) + } + } else { + pref[type] = character } } } diff --git a/packages/remark-lint-checkbox-content-indent/index.js b/packages/remark-lint-checkbox-content-indent/index.js index 17da26af..acbd9ce2 100644 --- a/packages/remark-lint-checkbox-content-indent/index.js +++ b/packages/remark-lint-checkbox-content-indent/index.js @@ -27,56 +27,58 @@ * 4:7-4:10: Checkboxes should be followed by a single character */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var vfileLocation = require('vfile-location'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var vfileLocation = require('vfile-location') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:checkbox-content-indent', checkboxContentIndent); +module.exports = rule( + 'remark-lint:checkbox-content-indent', + checkboxContentIndent +) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end + +var reason = 'Checkboxes should be followed by a single character' function checkboxContentIndent(tree, file) { - var contents = file.toString(); - var location = vfileLocation(file); + var contents = String(file) + var location = vfileLocation(file) - visit(tree, 'listItem', visitor); + visit(tree, 'listItem', visitor) function visitor(node) { - var initial; - var final; - var value; + var initial + var final + var value /* Exit early for items without checkbox. */ - if (node.checked !== Boolean(node.checked) || generated(node)) { - return; + if (typeof node.checked !== 'boolean' || generated(node)) { + return } - initial = start(node).offset; + initial = start(node).offset /* istanbul ignore next - hard to test, couldn’t find a case. */ - final = (node.children.length ? start(node.children[0]) : end(node)).offset; + final = (node.children.length ? start(node.children[0]) : end(node)).offset while (/[^\S\n]/.test(contents.charAt(final))) { - 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); + value = contents.slice(initial, final) + value = value.slice(value.indexOf(']') + 1) - if (value.length === 1) { - return; + if (value.length !== 1) { + file.message(reason, { + start: location.toPosition(final - value.length + 1), + end: location.toPosition(final) + }) } - - file.message('Checkboxes should be followed by a single character', { - start: location.toPosition(final - value.length + 1), - end: location.toPosition(final) - }); } } diff --git a/packages/remark-lint-code-block-style/index.js b/packages/remark-lint-code-block-style/index.js index a8da1d84..381ab0b0 100644 --- a/packages/remark-lint-code-block-style/index.js +++ b/packages/remark-lint-code-block-style/index.js @@ -91,65 +91,58 @@ * 1:1: Invalid code block style `invalid`: use either `'consistent'`, `'fenced'`, or `'indented'` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:code-block-style', codeBlockStyle); +module.exports = rule('remark-lint:code-block-style', codeBlockStyle) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end -var STYLES = { - null: true, - fenced: true, - indented: true -}; +var styles = {null: true, fenced: true, indented: true} -function codeBlockStyle(tree, file, preferred) { - var contents = file.toString(); +function codeBlockStyle(tree, file, pref) { + var contents = String(file) - preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; + pref = typeof pref === 'string' && pref !== 'consistent' ? pref : null - if (STYLES[preferred] !== true) { - file.fail('Invalid code block style `' + preferred + '`: use either `\'consistent\'`, `\'fenced\'`, or `\'indented\'`'); + if (styles[pref] !== true) { + file.fail( + 'Invalid code block style `' + + pref + + "`: use either `'consistent'`, `'fenced'`, or `'indented'`" + ) } - visit(tree, 'code', visitor); + visit(tree, 'code', visitor) function visitor(node) { - var current = check(node); - - if (!current) { - return; - } - - if (!preferred) { - preferred = current; - } else if (preferred !== current) { - file.message('Code blocks should be ' + preferred, node); + var current = check(node) + + if (current) { + if (!pref) { + pref = current + } else if (pref !== current) { + file.message('Code blocks should be ' + pref, node) + } } } /* Get the style of `node`. */ function check(node) { - var initial = start(node).offset; - var final = end(node).offset; + var initial = start(node).offset + var final = end(node).offset if (generated(node)) { - return null; - } - - if ( - node.lang || - /^\s*([~`])\1{2,}/.test(contents.slice(initial, final)) - ) { - return 'fenced'; + return null } - return 'indented'; + return node.lang || /^\s*([~`])\1{2,}/.test(contents.slice(initial, final)) + ? 'fenced' + : 'indented' } } diff --git a/packages/remark-lint-definition-case/index.js b/packages/remark-lint-definition-case/index.js index 0a47fe8a..ed07b80f 100644 --- a/packages/remark-lint-definition-case/index.js +++ b/packages/remark-lint-definition-case/index.js @@ -19,38 +19,36 @@ * 1:1-1:47: Do not use upper-case characters in definition labels */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:definition-case', definitionCase); +module.exports = rule('remark-lint:definition-case', definitionCase) -var LABEL = /^\s*\[((?:\\[\s\S]|[^[\]])+)]/; +var label = /^\s*\[((?:\\[\s\S]|[^[\]])+)]/ +var reason = 'Do not use upper-case characters in definition labels' function definitionCase(tree, file) { - var contents = file.toString(); + var contents = String(file) - visit(tree, 'definition', validate); - visit(tree, 'footnoteDefinition', validate); + visit(tree, ['definition', 'footnoteDefinition'], validate) /* Validate a node, either a normal definition or * a footnote definition. */ function validate(node) { - var start = position.start(node).offset; - var end = position.end(node).offset; - var label; + var start = position.start(node).offset + var end = position.end(node).offset + var value - if (generated(node)) { - return; - } - - label = contents.slice(start, end).match(LABEL)[1]; + if (!generated(node)) { + value = contents.slice(start, end).match(label)[1] - if (label !== label.toLowerCase()) { - file.message('Do not use upper-case characters in definition labels', node); + if (value !== value.toLowerCase()) { + file.message(reason, node) + } } } } diff --git a/packages/remark-lint-definition-spacing/index.js b/packages/remark-lint-definition-spacing/index.js index 2ebae095..c9d74845 100644 --- a/packages/remark-lint-definition-spacing/index.js +++ b/packages/remark-lint-definition-spacing/index.js @@ -19,36 +19,32 @@ * 1:1-1:57: Do not use consecutive white-space in definition labels */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:definition-spacing', definitionSpacing); +module.exports = rule('remark-lint:definition-spacing', definitionSpacing) -var LABEL = /^\s*\[((?:\\[\s\S]|[^[\]])+)]/; +var label = /^\s*\[((?:\\[\s\S]|[^[\]])+)]/ +var reason = 'Do not use consecutive white-space in definition labels' function definitionSpacing(tree, file) { - var contents = file.toString(); + var contents = String(file) - visit(tree, 'definition', validate); - visit(tree, 'footnoteDefinition', validate); + visit(tree, ['definition', 'footnoteDefinition'], validate) function validate(node) { - var start = position.start(node).offset; - var end = position.end(node).offset; - var label; - - if (generated(node)) { - return; - } - - label = contents.slice(start, end).match(LABEL)[1]; - - if (/[ \t\n]{2,}/.test(label)) { - file.message('Do not use consecutive white-space in definition labels', node); + var start = position.start(node).offset + var end = position.end(node).offset + + if ( + !generated(node) && + /[ \t\n]{2,}/.test(contents.slice(start, end).match(label)[1]) + ) { + file.message(reason, node) } } } diff --git a/packages/remark-lint-emphasis-marker/index.js b/packages/remark-lint-emphasis-marker/index.js index 27278f13..69632262 100644 --- a/packages/remark-lint-emphasis-marker/index.js +++ b/packages/remark-lint-emphasis-marker/index.js @@ -59,43 +59,45 @@ * 1:1: Invalid emphasis marker `invalid`: use either `'consistent'`, `'*'`, or `'_'` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:emphasis-marker', emphasisMarker); +module.exports = rule('remark-lint:emphasis-marker', emphasisMarker) -var MARKERS = { - '*': true, - _: true, - null: true -}; +var markers = {null: true, '*': true, _: true} -function emphasisMarker(tree, file, preferred) { - preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; +function emphasisMarker(tree, file, pref) { + var contents = String(file) - if (MARKERS[preferred] !== true) { - file.fail('Invalid emphasis marker `' + preferred + '`: use either `\'consistent\'`, `\'*\'`, or `\'_\'`'); + pref = typeof pref === 'string' && pref !== 'consistent' ? pref : null + + if (markers[pref] !== true) { + file.fail( + 'Invalid emphasis marker `' + + pref + + "`: use either `'consistent'`, `'*'`, or `'_'`" + ) } - visit(tree, 'emphasis', visitor); + visit(tree, 'emphasis', visitor) function visitor(node) { - var marker = file.toString().charAt(position.start(node).offset); + var marker - if (generated(node)) { - return; - } + if (!generated(node)) { + marker = contents.charAt(position.start(node).offset) - if (preferred) { - if (marker !== preferred) { - file.message('Emphasis should use `' + preferred + '` as a marker', node); + if (pref) { + if (marker !== pref) { + file.message('Emphasis should use `' + pref + '` as a marker', node) + } + } else { + pref = marker } - } else { - preferred = marker; } } } diff --git a/packages/remark-lint-fenced-code-flag/index.js b/packages/remark-lint-fenced-code-flag/index.js index f65aea3c..b1c633f2 100644 --- a/packages/remark-lint-fenced-code-flag/index.js +++ b/packages/remark-lint-fenced-code-flag/index.js @@ -64,48 +64,53 @@ * 1:1-3:4: Invalid code-language flag */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:fenced-code-flag', fencedCodeFlag); +module.exports = rule('remark-lint:fenced-code-flag', fencedCodeFlag) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end -function fencedCodeFlag(ast, file, preferred) { - var contents = file.toString(); - var allowEmpty = false; - var flags = []; +var fence = /^ {0,3}([~`])\1{2,}/ +var reasonInvalid = 'Invalid code-language flag' +var reasonMissing = 'Missing code-language flag' - if (typeof preferred === 'object' && !('length' in preferred)) { - allowEmpty = Boolean(preferred.allowEmpty); +function fencedCodeFlag(tree, file, pref) { + var contents = String(file) + var allowEmpty = false + var flags = [] - preferred = preferred.flags; + if (typeof pref === 'object' && !('length' in pref)) { + allowEmpty = Boolean(pref.allowEmpty) + pref = pref.flags } - if (typeof preferred === 'object' && 'length' in preferred) { - flags = String(preferred).split(','); + if (typeof pref === 'object' && 'length' in pref) { + flags = String(pref).split(',') } - visit(ast, 'code', visitor); + visit(tree, 'code', visitor) function visitor(node) { - var value = contents.slice(start(node).offset, end(node).offset); + var value - if (generated(node)) { - return; - } + if (!generated(node)) { + if (node.lang) { + if (flags.length !== 0 && flags.indexOf(node.lang) === -1) { + file.message(reasonInvalid, node) + } + } else { + value = contents.slice(start(node).offset, end(node).offset) - if (node.lang) { - if (flags.length !== 0 && flags.indexOf(node.lang) === -1) { - file.message('Invalid code-language flag', node); + if (!allowEmpty && fence.test(value)) { + file.message(reasonMissing, node) + } } - } else if (/^ {0,3}([~`])\1{2,}/.test(value) && !allowEmpty) { - file.message('Missing code-language flag', node); } } } diff --git a/packages/remark-lint-fenced-code-marker/index.js b/packages/remark-lint-fenced-code-marker/index.js index a6e1dfaa..dfc19916 100644 --- a/packages/remark-lint-fenced-code-marker/index.js +++ b/packages/remark-lint-fenced-code-marker/index.js @@ -66,52 +66,58 @@ * 1:1: Invalid fenced code marker `!`: use either `'consistent'`, `` '`' ``, or `'~'` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:fenced-code-marker', fencedCodeMarker); +module.exports = rule('remark-lint:fenced-code-marker', fencedCodeMarker) -var MARKERS = { +var markers = { '`': true, '~': true, null: true -}; +} -function fencedCodeMarker(ast, file, preferred) { - var contents = file.toString(); +function fencedCodeMarker(tree, file, pref) { + var contents = String(file) - preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; + pref = typeof pref === 'string' && pref !== 'consistent' ? pref : null - if (MARKERS[preferred] !== true) { - file.fail('Invalid fenced code marker `' + preferred + '`: use either `\'consistent\'`, `` \'`\' ``, or `\'~\'`'); + if (markers[pref] !== true) { + file.fail( + 'Invalid fenced code marker `' + + pref + + "`: use either `'consistent'`, `` '`' ``, or `'~'`" + ) } - visit(ast, 'code', visitor); + visit(tree, 'code', visitor) function visitor(node) { - var marker = contents.substr(position.start(node).offset, 4); - - if (generated(node)) { - return; - } + var marker - marker = marker.trimLeft().charAt(0); - - /* Ignore unfenced code blocks. */ - if (MARKERS[marker] !== true) { - return; - } + if (!generated(node)) { + marker = contents + .substr(position.start(node).offset, 4) + .trimLeft() + .charAt(0) - if (preferred) { - if (marker !== preferred) { - file.message('Fenced code should use ' + preferred + ' as a marker', node); + /* Ignore unfenced code blocks. */ + if (markers[marker] === true) { + if (pref) { + if (marker !== pref) { + file.message( + 'Fenced code should use ' + pref + ' as a marker', + node + ) + } + } else { + pref = marker + } } - } else { - preferred = marker; } } } diff --git a/packages/remark-lint-file-extension/index.js b/packages/remark-lint-file-extension/index.js index fd5c0368..2a538921 100644 --- a/packages/remark-lint-file-extension/index.js +++ b/packages/remark-lint-file-extension/index.js @@ -22,22 +22,18 @@ * @example {"name": "readme.mkd", "setting": "mkd"} */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); +var rule = require('unified-lint-rule') -module.exports = rule('remark-lint:file-extension', fileExtension); +module.exports = rule('remark-lint:file-extension', fileExtension) -function fileExtension(ast, file, preferred) { - var ext = file.extname; +function fileExtension(tree, file, pref) { + var ext = file.extname - if (ext) { - ext = ext.slice(1); - } - - preferred = typeof preferred === 'string' ? preferred : 'md'; + pref = typeof pref === 'string' ? pref : 'md' - if (ext && ext !== preferred) { - file.message('Invalid extension: use `' + preferred + '`'); + if (ext && ext.slice(1) !== pref) { + file.message('Invalid extension: use `' + pref + '`') } } diff --git a/packages/remark-lint-final-definition/index.js b/packages/remark-lint-final-definition/index.js index 9010d49c..16f68f9a 100644 --- a/packages/remark-lint-final-definition/index.js +++ b/packages/remark-lint-final-definition/index.js @@ -25,36 +25,41 @@ * 3:1-3:47: Move definitions to the end of the file (after the node at line `5`) */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:final-definition', finalDefinition); +module.exports = rule('remark-lint:final-definition', finalDefinition) -var start = position.start; +var start = position.start -function finalDefinition(ast, file) { - var last = null; +function finalDefinition(tree, file) { + var last = null - visit(ast, visitor, true); + visit(tree, visitor, true) function visitor(node) { - var line = start(node).line; + var line = start(node).line /* Ignore generated nodes. */ if (node.type === 'root' || generated(node)) { - return; + return } if (node.type === 'definition') { if (last !== null && last > line) { - file.message('Move definitions to the end of the file (after the node at line `' + last + '`)', node); + file.message( + 'Move definitions to the end of the file (after the node at line `' + + last + + '`)', + node + ) } } else if (last === null) { - last = line; + last = line } } } diff --git a/packages/remark-lint-final-newline/index.js b/packages/remark-lint-final-newline/index.js index 59218b47..5cc3b0f5 100644 --- a/packages/remark-lint-final-newline/index.js +++ b/packages/remark-lint-final-newline/index.js @@ -49,17 +49,17 @@ * ``` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); +var rule = require('unified-lint-rule') -module.exports = rule('remark-lint:final-newline', finalNewline); +module.exports = rule('remark-lint:final-newline', finalNewline) -function finalNewline(ast, file) { - var contents = file.toString(); - var last = contents.length - 1; +function finalNewline(tree, file) { + var contents = String(file) + var last = contents.length - 1 if (last > -1 && contents.charAt(last) !== '\n') { - file.message('Missing newline character at end of file'); + file.message('Missing newline character at end of file') } } diff --git a/packages/remark-lint-first-heading-level/index.js b/packages/remark-lint-first-heading-level/index.js index 9c9341a1..31548ae8 100644 --- a/packages/remark-lint-first-heading-level/index.js +++ b/packages/remark-lint-first-heading-level/index.js @@ -77,45 +77,43 @@ * 1:1-1:14: First heading level should be `2` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:first-heading-level', firstHeadingLevel); +module.exports = rule('remark-lint:first-heading-level', firstHeadingLevel) -var re = / 2) { - file.message('Use two spaces for hard line breaks', node); + if (value.length > 2) { + file.message(reason, node) + } } } } diff --git a/packages/remark-lint-heading-increment/index.js b/packages/remark-lint-heading-increment/index.js index de76dc32..95ece90a 100644 --- a/packages/remark-lint-heading-increment/index.js +++ b/packages/remark-lint-heading-increment/index.js @@ -23,30 +23,32 @@ * 3:1-3:10: Heading levels should increment by one level at a time */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:heading-increment', headingIncrement); +module.exports = rule('remark-lint:heading-increment', headingIncrement) -function headingIncrement(ast, file) { - var prev = null; +var reason = 'Heading levels should increment by one level at a time' - visit(ast, 'heading', visitor); +function headingIncrement(tree, file) { + var prev = null + + visit(tree, 'heading', visitor) function visitor(node) { - var depth = node.depth; + var depth - if (generated(node)) { - return; - } + if (!generated(node)) { + depth = node.depth - if (prev && depth > prev + 1) { - file.message('Heading levels should increment by one level at a time', node); - } + if (prev && depth > prev + 1) { + file.message(reason, node) + } - prev = depth; + prev = depth + } } } diff --git a/packages/remark-lint-heading-style/index.js b/packages/remark-lint-heading-style/index.js index 81c28ab3..5c10a469 100644 --- a/packages/remark-lint-heading-style/index.js +++ b/packages/remark-lint-heading-style/index.js @@ -64,33 +64,31 @@ * 6:1-6:13: Headings should use setext */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var style = require('mdast-util-heading-style'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var style = require('mdast-util-heading-style') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:heading-style', headingStyle); +module.exports = rule('remark-lint:heading-style', headingStyle) -var TYPES = ['atx', 'atx-closed', 'setext']; +var types = ['atx', 'atx-closed', 'setext'] -function headingStyle(ast, file, preferred) { - preferred = TYPES.indexOf(preferred) === -1 ? null : preferred; +function headingStyle(tree, file, pref) { + pref = types.indexOf(pref) === -1 ? null : pref - visit(ast, 'heading', visitor); + visit(tree, 'heading', visitor) function visitor(node) { - if (generated(node)) { - return; - } - - if (preferred) { - if (style(node, preferred) !== preferred) { - file.message('Headings should use ' + preferred, node); + if (!generated(node)) { + if (pref) { + if (style(node, pref) !== pref) { + file.message('Headings should use ' + pref, node) + } + } else { + pref = style(node, pref) } - } else { - preferred = style(node, preferred); } } } diff --git a/packages/remark-lint-linebreak-style/index.js b/packages/remark-lint-linebreak-style/index.js index 7789c3cb..c6e7b9ae 100644 --- a/packages/remark-lint-linebreak-style/index.js +++ b/packages/remark-lint-linebreak-style/index.js @@ -45,46 +45,49 @@ * 1:6: Expected linebreaks to be windows (`\r\n`), not unix (`\n`) */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var location = require('vfile-location'); +var rule = require('unified-lint-rule') +var location = require('vfile-location') -module.exports = rule('remark-lint:linebreak-style', linebreakStyle); +module.exports = rule('remark-lint:linebreak-style', linebreakStyle) -var sequences = { - unix: '\n', - windows: '\r\n' -}; +var sequences = {unix: '\n', windows: '\r\n'} +var escaped = {unix: '\\n', windows: '\\r\\n'} +var types = {true: 'windows', false: 'unix'} -var escaped = { - unix: '\\n', - windows: '\\r\\n' -}; +function linebreakStyle(tree, file, pref) { + var content = String(file) + var position = location(content).toPosition + var index = content.indexOf('\n') + var type + var reason -function linebreakStyle(ast, file, preferred) { - var content = String(file); - var position = location(content).toPosition; - var index = content.indexOf('\n'); - var type; - - preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; + pref = typeof pref === 'string' && pref !== 'consistent' ? pref : null while (index !== -1) { - type = content.charAt(index - 1) === '\r' ? 'windows' : 'unix'; + type = types[content.charAt(index - 1) === '\r'] + + if (pref) { + if (sequences[pref] !== sequences[type]) { + reason = + 'Expected linebreaks to be ' + + pref + + ' (`' + + escaped[pref] + + '`), ' + + 'not ' + + type + + ' (`' + + escaped[type] + + '`)' - if (preferred) { - if (sequences[preferred] !== sequences[type]) { - file.message( - 'Expected linebreaks to be ' + preferred + ' (`' + escaped[preferred] + '`), ' + - 'not ' + type + ' (`' + escaped[type] + '`)', - position(index) - ); + file.message(reason, position(index)) } } else { - preferred = type; + pref = type } - index = content.indexOf('\n', index + 1); + index = content.indexOf('\n', index + 1) } } diff --git a/packages/remark-lint-link-title-style/index.js b/packages/remark-lint-link-title-style/index.js index 3bc589b8..044427ae 100644 --- a/packages/remark-lint-link-title-style/index.js +++ b/packages/remark-lint-link-title-style/index.js @@ -67,77 +67,75 @@ * 1:1: Invalid link title style marker `.`: use either `'consistent'`, `'"'`, `'\''`, or `'()'` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var vfileLocation = require('vfile-location'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var vfileLocation = require('vfile-location') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:link-title-style', linkTitleStyle); +module.exports = rule('remark-lint:link-title-style', linkTitleStyle) -var end = position.end; +var end = position.end -var MARKERS = { - '"': true, - '\'': true, - ')': true, - null: true -}; +var markers = {'"': true, "'": true, ')': true, null: true} -function linkTitleStyle(ast, file, preferred) { - var contents = file.toString(); - var location = vfileLocation(file); +function linkTitleStyle(tree, file, pref) { + var contents = String(file) + var location = vfileLocation(file) - preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; + pref = typeof pref === 'string' && pref !== 'consistent' ? pref : null + pref = pref === '()' || pref === '(' ? ')' : pref - if (preferred === '()' || preferred === '(') { - preferred = ')'; + if (markers[pref] !== true) { + file.fail( + 'Invalid link title style marker `' + + pref + + "`: use either `'consistent'`, `'\"'`, `'\\''`, or `'()'`" + ) } - if (MARKERS[preferred] !== true) { - file.fail('Invalid link title style marker `' + preferred + '`: use either `\'consistent\'`, `\'"\'`, `\'\\\'\'`, or `\'()\'`'); - } - - visit(ast, 'link', validate); - visit(ast, 'image', validate); - visit(ast, 'definition', validate); + visit(tree, ['link', 'image', 'definition'], validate) function validate(node) { - var last = end(node).offset - 1; - var character; - var pos; + var last = end(node).offset - 1 + var character + var reason if (generated(node)) { - return; + return } if (node.type !== 'definition') { - last--; + last-- } while (last) { - character = contents.charAt(last); + character = contents.charAt(last) /* istanbul ignore if - remark before 8.0.0 */ if (/\s/.test(character)) { - last--; + last-- } else { - break; + break } } - /* Not a title. */ - if (!(character in MARKERS)) { - return; - } - - if (!preferred) { - preferred = character; - } else if (preferred !== character) { - pos = location.toPosition(last + 1); - file.message('Titles should use `' + (preferred === ')' ? '()' : preferred) + '` as a quote', pos); + /* Skip non-titles. */ + if (character in markers) { + if (pref) { + if (pref !== character) { + reason = + 'Titles should use `' + + (pref === ')' ? '()' : pref) + + '` as a quote' + + file.message(reason, location.toPosition(last + 1)) + } + } else { + pref = character + } } } } diff --git a/packages/remark-lint-list-item-bullet-indent/index.js b/packages/remark-lint-list-item-bullet-indent/index.js index f5261abb..e2392a4c 100644 --- a/packages/remark-lint-list-item-bullet-indent/index.js +++ b/packages/remark-lint-list-item-bullet-indent/index.js @@ -34,48 +34,52 @@ * 4:3: Incorrect indentation before bullet: remove 1 space */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var plural = require('plur'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var plural = require('plur') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:list-item-bullet-indent', listItemBulletIndent); +module.exports = rule( + 'remark-lint:list-item-bullet-indent', + listItemBulletIndent +) -var start = position.start; +var start = position.start -function listItemBulletIndent(ast, file) { - var contents = file.toString(); +function listItemBulletIndent(tree, file) { + var contents = String(file) - visit(ast, 'list', visitor); + visit(tree, 'list', visitor) function visitor(node) { - var items = node.children; - - items.forEach(visitItems); + node.children.forEach(visitItems) } function visitItems(item) { - var head = item.children[0]; - var initial = start(item).offset; - var final = start(head).offset; - var indent; - - if (generated(item)) { - return; - } + var final + var indent + var reason - indent = contents.slice(initial, final).match(/^\s*/)[0].length; + if (!generated(item)) { + final = start(item.children[0]) + indent = contents.slice(start(item).offset, final.offset).match(/^\s*/)[0] + .length - if (indent !== 0) { - initial = start(head); + if (indent !== 0) { + reason = + 'Incorrect indentation before bullet: remove ' + + indent + + ' ' + + plural('space', indent) - file.message('Incorrect indentation before bullet: remove ' + indent + ' ' + plural('space', indent), { - line: initial.line, - column: initial.column - indent - }); + file.message(reason, { + line: final.line, + column: final.column - indent + }) + } } } } diff --git a/packages/remark-lint-list-item-content-indent/index.js b/packages/remark-lint-list-item-content-indent/index.js index 3e5c4123..0716162d 100644 --- a/packages/remark-lint-list-item-content-indent/index.js +++ b/packages/remark-lint-list-item-content-indent/index.js @@ -21,39 +21,46 @@ * 2:5: Don’t use mixed indentation for children, remove 1 space */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var plural = require('plur'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var plural = require('plur') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:list-item-content-indent', listItemContentIndent); +module.exports = rule( + 'remark-lint:list-item-content-indent', + listItemContentIndent +) -var start = position.start; +var start = position.start -function listItemContentIndent(ast, file) { - var contents = file.toString(); +function listItemContentIndent(tree, file) { + var contents = String(file) - visit(ast, 'listItem', visitor); + visit(tree, 'listItem', visitor) function visitor(node) { - var style; + var style - node.children.forEach(visitItem); + node.children.forEach(visitItem) function visitItem(item, index) { - var begin = start(item); - var column = begin.column; - var char; - var diff; - var word; + var begin + var column + var char + var diff + var absDiff + var reason if (generated(item)) { - return; + return } + begin = start(item) + column = begin.column + /* Get indentation for the first child. * Only the first item can have a checkbox, * so here we remove that from the column. */ @@ -61,37 +68,39 @@ function listItemContentIndent(ast, file) { /* If there’s a checkbox before the content, * look backwards to find the start of that * checkbox. */ - if (Boolean(node.checked) === node.checked) { - char = begin.offset - 1; + if (typeof node.checked === 'boolean') { + char = begin.offset - 1 while (contents.charAt(char) !== '[') { - char--; + char-- } - column -= begin.offset - char; + column -= begin.offset - char } - style = column; + style = column - return; + return } /* Warn for violating children. */ if (column !== style) { - diff = style - column; - /* istanbul ignore next - hard to test, I couldn’t find it at least. */ - word = diff > 0 ? 'add' : 'remove'; - - diff = Math.abs(diff); - - file.message( - 'Don’t use mixed indentation for children, ' + word + - ' ' + diff + ' ' + plural('space', diff), - { - line: start(item).line, - column: column - } - ); + diff = style - column + absDiff = Math.abs(diff) + + reason = + 'Don’t use mixed indentation for children, ' + + /* istanbul ignore next - hard to test, I couldn’t find it at least. */ + (diff > 0 ? 'add' : 'remove') + + ' ' + + absDiff + + ' ' + + plural('space', absDiff) + + file.message(reason, { + line: start(item).line, + column: column + }) } } } diff --git a/packages/remark-lint-list-item-indent/index.js b/packages/remark-lint-list-item-indent/index.js index 24c28f3b..cd8ab5d5 100644 --- a/packages/remark-lint-list-item-indent/index.js +++ b/packages/remark-lint-list-item-indent/index.js @@ -101,82 +101,76 @@ * 1:1: Invalid list-item indent style `invalid`: use either `'tab-size'`, `'space'`, or `'mixed'` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var plural = require('plur'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var plural = require('plur') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:list-item-indent', listItemIndent); +module.exports = rule('remark-lint:list-item-indent', listItemIndent) -var start = position.start; +var start = position.start -var STYLES = { - 'tab-size': true, - mixed: true, - space: true -}; +var styles = {'tab-size': true, mixed: true, space: true} -function listItemIndent(ast, file, preferred) { - var contents = file.toString(); +function listItemIndent(tree, file, pref) { + var contents = String(file) - preferred = typeof preferred === 'string' ? preferred : 'tab-size'; + pref = typeof pref === 'string' ? pref : 'tab-size' - if (STYLES[preferred] !== true) { - file.fail('Invalid list-item indent style `' + preferred + '`: use either `\'tab-size\'`, `\'space\'`, or `\'mixed\'`'); + if (styles[pref] !== true) { + file.fail( + 'Invalid list-item indent style `' + + pref + + "`: use either `'tab-size'`, `'space'`, or `'mixed'`" + ) } - visit(ast, 'list', visitor); + visit(tree, 'list', visitor) function visitor(node) { - var items = node.children; + var loose = node.loose - if (generated(node)) { - return; + if (!generated(node)) { + node.children.forEach(visitItem) } - items.forEach(visitItem); - function visitItem(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.message( - 'Incorrect list-item indent: ' + word + - ' ' + diff + ' ' + plural('space', diff), - start(head) - ); + var head = item.children[0] + var final = start(head) + var marker + var bulletSize + var style + var diff + var absDiff + var reason + + marker = contents + .slice(start(item).offset, final.offset) + .replace(/\[[x ]?]\s*$/i, '') + + bulletSize = marker.trimRight().length + + style = + pref === 'tab-size' || (pref === 'mixed' && loose) + ? Math.ceil(bulletSize / 4) * 4 + : bulletSize + 1 + + if (marker.length !== style) { + diff = style - marker.length + absDiff = Math.abs(diff) + + reason = + 'Incorrect list-item indent: ' + + (diff > 0 ? 'add' : 'remove') + + ' ' + + absDiff + + ' ' + + plural('space', absDiff) + + file.message(reason, final) } } } diff --git a/packages/remark-lint-list-item-spacing/index.js b/packages/remark-lint-list-item-spacing/index.js index f9228532..113c8d1a 100644 --- a/packages/remark-lint-list-item-spacing/index.js +++ b/packages/remark-lint-list-item-spacing/index.js @@ -107,103 +107,90 @@ * 15:1-16:1: Extraneous new line after list item */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:list-item-spacing', listItemSpacing); +module.exports = rule('remark-lint:list-item-spacing', listItemSpacing) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end -function listItemSpacing(ast, file, preferred) { - var blanks = Boolean( - preferred && - typeof preferred === 'object' && - preferred.checkBlanks - ); +var reasonLoose = 'Missing new line after list item' +var reasonTight = 'Extraneous new line after list item' - visit(ast, 'list', visitor); +function listItemSpacing(tree, file, pref) { + var blanks = pref && typeof pref === 'object' && Boolean(pref.checkBlanks) + var fn = blanks ? inferBlankLine : inferMultiline - function visitor(node) { - var items = node.children; - var isTightList = true; - var indent = start(node).column; - var type; - - if (generated(node)) { - return; - } - - items.forEach(infer); + visit(tree, 'list', visitor) - type = isTightList ? 'tight' : 'loose'; - - items.forEach(warn); - - function infer(item) { - var fn = blanks ? inferBlankLine : inferMultiline; + function visitor(node) { + var tight = true + var indent + var children + var length + var index + var child + var next + + if (!generated(node)) { + children = node.children + length = children.length + index = -1 - if (fn(item)) { - isTightList = false; + while (++index < length) { + if (fn(children[index])) { + tight = false + break + } } - } - function inferBlankLine(item) { - var children = item.children; - var length = children.length; - var index = 0; - var child = children[index]; - var next; + indent = start(node).column + child = children[0] + index = 0 while (++index < length) { - next = children[index]; + next = children[index] - /* All children in `listItem`s are block. */ - if ((start(next).line - end(child).line) > 1) { - return true; + if (end(child).column > indent !== tight) { + file.message(tight ? reasonTight : reasonLoose, { + start: end(child), + end: start(next) + }) } - child = next; + child = next } - - return false; - } - - function inferMultiline(item) { - var content = item.children; - var head = content[0]; - var tail = content[content.length - 1]; - return (end(tail).line - start(head).line) > 0; } + } +} - function warn(item, index) { - var next = items[index + 1]; - var isTight = end(item).column > indent; +function inferBlankLine(node) { + var children = node.children + var child = children[0] + var length = children.length + var index = 0 + var next - /* Ignore last. */ - if (!next) { - return; - } + while (++index < length) { + next = children[index] - /* Check if the list item's state does (not) - * match the list's state. */ - if (isTight !== isTightList) { - if (type === 'loose') { - file.message('Missing new line after list item', { - start: end(item), - end: start(next) - }); - } else { - file.message('Extraneous new line after list item', { - start: end(item), - end: start(next) - }); - } - } + /* All children in `listItem`s are block. */ + if (start(next).line - end(child).line > 1) { + return true } + + child = next } + + return false +} + +function inferMultiline(node) { + var children = node.children + return end(children[children.length - 1]).line - start(children[0]).line > 0 } diff --git a/packages/remark-lint-maximum-heading-length/index.js b/packages/remark-lint-maximum-heading-length/index.js index fc601ea7..c6a22150 100644 --- a/packages/remark-lint-maximum-heading-length/index.js +++ b/packages/remark-lint-maximum-heading-length/index.js @@ -25,27 +25,26 @@ * 1:1-1:52: Use headings shorter than `40` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var generated = require('unist-util-generated'); -var toString = require('mdast-util-to-string'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var generated = require('unist-util-generated') +var toString = require('mdast-util-to-string') -module.exports = rule('remark-lint:maximum-heading-length', maximumHeadingLength); +module.exports = rule( + 'remark-lint:maximum-heading-length', + maximumHeadingLength +) -function maximumHeadingLength(ast, file, preferred) { - preferred = isNaN(preferred) || typeof preferred !== 'number' ? 60 : preferred; +function maximumHeadingLength(tree, file, pref) { + pref = typeof pref === 'number' && !isNaN(pref) ? pref : 60 - visit(ast, 'heading', visitor); + visit(tree, 'heading', visitor) function visitor(node) { - if (generated(node)) { - return; - } - - if (toString(node).length > preferred) { - file.message('Use headings shorter than `' + preferred + '`', node); + if (!generated(node) && toString(node).length > pref) { + file.message('Use headings shorter than `' + pref + '`', node) } } } diff --git a/packages/remark-lint-maximum-line-length/index.js b/packages/remark-lint-maximum-line-length/index.js index ff77e31d..8b699f66 100644 --- a/packages/remark-lint-maximum-line-length/index.js +++ b/packages/remark-lint-maximum-line-length/index.js @@ -83,63 +83,38 @@ * 4:12: Line must be at most 10 characters */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:maximum-line-length', maximumLineLength); +module.exports = rule('remark-lint:maximum-line-length', maximumLineLength) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end -function maximumLineLength(ast, file, preferred) { - var style = preferred && preferred !== true ? preferred : 80; - var content = file.toString(); - var matrix = content.split(/\r?\n/); - var index = -1; - var length = matrix.length; - var lineLength; +function maximumLineLength(tree, file, pref) { + var style = typeof pref === 'number' && !isNaN(pref) ? pref : 80 + var content = String(file) + var lines = content.split(/\r?\n/) + var length = lines.length + var index = -1 + var lineLength - /* Next, white list nodes which cannot be wrapped. */ - visit(ast, ignore); + visit(tree, ['heading', 'table', 'code', 'definition'], ignore) + visit(tree, ['link', 'image'], validateLink) - visit(ast, 'link', validateLink); - visit(ast, 'image', validateLink); - - /* Iterate over every line, and warn for - * violating lines. */ + /* Iterate over every line, and warn for violating lines. */ while (++index < length) { - lineLength = matrix[index].length; + lineLength = lines[index].length if (lineLength > style) { file.message('Line must be at most ' + style + ' characters', { line: index + 1, column: lineLength + 1 - }); - } - } - - function ignore(node) { - var applicable = isIgnored(node); - var initial = applicable && start(node).line; - var final = applicable && end(node).line; - - if (!applicable || generated(node)) { - return; - } - - whitelist(initial - 1, final); - } - - /* Whitelist from `initial` to `final`, zero-based. */ - function whitelist(initial, final) { - initial--; - - while (++initial < final) { - matrix[initial] = ''; + }) } } @@ -148,21 +123,21 @@ function maximumLineLength(ast, file, preferred) { * there’s white-space after it, they are not * whitelisted. */ function validateLink(node, pos, parent) { - var next = parent.children[pos + 1]; - var initial = start(node); - var final = end(node); + var next = parent.children[pos + 1] + var initial + var final - /* Nothing to whitelist when generated. */ - /* istanbul ignore if - Hard to test, as we only run this - * case on `position: true` */ + /* istanbul ignore if - Nothing to whitelist when generated. */ if (generated(node)) { - return; + return } - /* No whitelisting when starting after the border, - * or ending before it. */ + initial = start(node) + final = end(node) + + /* No whitelisting when starting after the border, or ending before it. */ if (initial.column > style || final.column < style) { - return; + return } /* No whitelisting when there’s white-space after @@ -172,18 +147,23 @@ function maximumLineLength(ast, file, preferred) { start(next).line === initial.line && (!next.value || /^(.+?[ \t].+?)/.test(next.value)) ) { - return; + return } - whitelist(initial.line - 1, final.line); + whitelist(initial.line - 1, final.line) } -} -/* Check if `node` is applicable, as in, if it should be - * ignored. */ -function isIgnored(node) { - return node.type === 'heading' || - node.type === 'table' || - node.type === 'code' || - node.type === 'definition'; + function ignore(node) { + /* istanbul ignore else - Hard to test, as we only run this case on `position: true` */ + if (!generated(node)) { + whitelist(start(node).line - 1, end(node).line) + } + } + + /* Whitelist from `initial` to `final`, zero-based. */ + function whitelist(initial, final) { + while (initial < final) { + lines[initial++] = '' + } + } } diff --git a/packages/remark-lint-no-auto-link-without-protocol/index.js b/packages/remark-lint-no-auto-link-without-protocol/index.js index 3a38836f..064fb3db 100644 --- a/packages/remark-lint-no-auto-link-without-protocol/index.js +++ b/packages/remark-lint-no-auto-link-without-protocol/index.js @@ -31,38 +31,44 @@ * 1:1-1:14: All automatic links must start with a protocol */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); -var toString = require('mdast-util-to-string'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') +var toString = require('mdast-util-to-string') -module.exports = rule('remark-lint:no-auto-link-without-protocol', noAutoLinkWithoutProtocol); +module.exports = rule( + 'remark-lint:no-auto-link-without-protocol', + noAutoLinkWithoutProtocol +) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end /* Protocol expression. See: * http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax */ -var PROTOCOL = /^[a-z][a-z+.-]+:\/?/i; +var protocol = /^[a-z][a-z+.-]+:\/?/i -function noAutoLinkWithoutProtocol(ast, file) { - visit(ast, 'link', visitor); +var reason = 'All automatic links must start with a protocol' + +function noAutoLinkWithoutProtocol(tree, file) { + visit(tree, 'link', visitor) function visitor(node) { - var head = start(node.children[0]).column; - var tail = end(node.children[node.children.length - 1]).column; - var initial = start(node).column; - var final = end(node).column; + var children - if (generated(node)) { - return; - } + if (!generated(node)) { + children = node.children - if (initial === head - 1 && final === tail + 1 && !PROTOCOL.test(toString(node))) { - file.message('All automatic links must start with a protocol', node); + if ( + start(node).column === start(children[0]).column - 1 && + end(node).column === end(children[children.length - 1]).column + 1 && + !protocol.test(toString(node)) + ) { + file.message(reason, node) + } } } } diff --git a/packages/remark-lint-no-blockquote-without-marker/index.js b/packages/remark-lint-no-blockquote-without-marker/index.js index ae1deabd..279ae5c2 100644 --- a/packages/remark-lint-no-blockquote-without-marker/index.js +++ b/packages/remark-lint-no-blockquote-without-marker/index.js @@ -31,58 +31,64 @@ * 2:1: Missing marker in blockquote */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var vfileLocation = require('vfile-location'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var vfileLocation = require('vfile-location') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:no-blockquote-without-marker', noBlockquoteWithoutMarker); +module.exports = rule( + 'remark-lint:no-blockquote-without-marker', + noBlockquoteWithoutMarker +) -function noBlockquoteWithoutMarker(ast, file) { - var contents = file.toString(); - var location = vfileLocation(file); - var last = contents.length; +var reason = 'Missing marker in blockquote' - visit(ast, 'blockquote', visitor); +function noBlockquoteWithoutMarker(tree, file) { + var contents = String(file) + var location = vfileLocation(file) + var last = contents.length + + visit(tree, 'blockquote', visitor) function visitor(node) { - var start = position.start(node).line; - var indent = node.position && node.position.indent; + var indent = node.position && node.position.indent + var start + var length + var index + var line + var offset + var character + var pos if (generated(node) || !indent || indent.length === 0) { - return; + return } - indent.forEach(eachLine); + start = position.start(node).line + length = indent.length + index = -1 - function eachLine(column, n) { - var character; - var line = start + n + 1; - var offset = location.toOffset({ - line: line, - column: column - }) - 1; + while (++index < length) { + line = start + index + 1 + pos = {line: line, column: indent[index]} + offset = location.toOffset(pos) - 1 while (++offset < last) { - character = contents.charAt(offset); + character = contents.charAt(offset) if (character === '>') { - return; + break } /* istanbul ignore else - just for safety */ if (character !== ' ' && character !== '\t') { - break; + file.message(reason, pos) + break } } - - file.message('Missing marker in blockquote', { - line: line, - column: column - }); } } } diff --git a/packages/remark-lint-no-consecutive-blank-lines/index.js b/packages/remark-lint-no-consecutive-blank-lines/index.js index 652ca740..4975f0cf 100644 --- a/packages/remark-lint-no-consecutive-blank-lines/index.js +++ b/packages/remark-lint-no-consecutive-blank-lines/index.js @@ -31,84 +31,98 @@ * ␊ * bravo(); * + * @example {"name": "empty-document.md"} + * * @example {"name": "invalid.md", "label": "input"} * * Foo... * ␊ * ␊ - * ...Bar. + * ...Bar + * ␊ + * ␊ * * @example {"name": "invalid.md", "label": "output"} * * 4:1: Remove 1 line before node + * 4:7: Remove 2 lines after node */ -'use strict'; - -var rule = require('unified-lint-rule'); -var plural = require('plur'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +'use strict' -module.exports = rule('remark-lint:no-consecutive-blank-lines', noConsecutiveBlankLines); +var rule = require('unified-lint-rule') +var plural = require('plur') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -var MAX = 2; +module.exports = rule( + 'remark-lint:no-consecutive-blank-lines', + noConsecutiveBlankLines +) -function noConsecutiveBlankLines(ast, file) { - visit(ast, visitor); +function noConsecutiveBlankLines(tree, file) { + visit(tree, visitor) function visitor(node) { - var children = node.children; - var head = children && children[0]; - var tail = children && children[children.length - 1]; + var children = node.children + var head + var tail - if (generated(node)) { - return; - } + if (!generated(node) && children) { + head = children[0] - if (head && !generated(head)) { - /* Compare parent and first child. */ - compare(position.start(node), position.start(head), 0); + if (head && !generated(head)) { + /* Compare parent and first child. */ + compare(position.start(node), position.start(head), 0) - /* Compare between each child. */ - children.forEach(visitChild); + /* Compare between each child. */ + children.forEach(visitChild) - /* Compare parent and last child. */ - if (tail !== head && !generated(tail)) { - compare(position.end(node), position.end(tail), 1); + tail = children[children.length - 1] + + /* Compare parent and last child. */ + if (tail !== head && !generated(tail)) { + compare(position.end(node), position.end(tail), 1) + } } } + } - function visitChild(child, index) { - var prev = children[index - 1]; - var max = MAX; + /* Compare the difference between `start` and `end`, + * and warn when that difference exceeds `max`. */ + function compare(start, end, max) { + var diff = end.line - start.line + var lines = Math.abs(diff) - max + var reason + + if (lines > 0) { + reason = + 'Remove ' + + lines + + ' ' + + plural('line', lines) + + ' ' + + (diff > 0 ? 'before' : 'after') + + ' node' + + file.message(reason, end) + } + } - if (!prev || generated(prev) || generated(child)) { - return; - } + function visitChild(child, index, all) { + var prev = all[index - 1] + var max = 2 + if (prev && !generated(prev) && !generated(child)) { if ( (prev.type === 'list' && child.type === 'list') || (child.type === 'code' && prev.type === 'list' && !child.lang) ) { - max++; + max++ } - compare(position.end(prev), position.start(child), max); - } - } - - /* Compare the difference between `start` and `end`, - * and warn when that difference exceeds `max`. */ - 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.message('Remove ' + diff + ' ' + plural('line', diff) + ' ' + word + ' node', end); + compare(position.end(prev), position.start(child), max) } } } diff --git a/packages/remark-lint-no-consecutive-blank-lines/readme.md b/packages/remark-lint-no-consecutive-blank-lines/readme.md index d66eadde..f507aeba 100644 --- a/packages/remark-lint-no-consecutive-blank-lines/readme.md +++ b/packages/remark-lint-no-consecutive-blank-lines/readme.md @@ -59,6 +59,12 @@ Paragraph. No messages. +##### `empty-document.md` + +###### Out + +No messages. + ##### `invalid.md` ###### In @@ -69,13 +75,16 @@ Note: `␊` represents a line feed. Foo... ␊ ␊ -...Bar. +...Bar +␊ +␊ ``` ###### Out ```text 4:1: Remove 1 line before node +4:7: Remove 2 lines after node ``` ## Install diff --git a/packages/remark-lint-no-duplicate-definitions/index.js b/packages/remark-lint-no-duplicate-definitions/index.js index a40e377a..fe8149a4 100644 --- a/packages/remark-lint-no-duplicate-definitions/index.js +++ b/packages/remark-lint-no-duplicate-definitions/index.js @@ -21,39 +21,40 @@ * 2:1-2:11: Do not use definitions with the same identifier (1:1) */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); -var visit = require('unist-util-visit'); +var rule = require('unified-lint-rule') +var position = require('unist-util-position') +var generated = require('unist-util-generated') +var visit = require('unist-util-visit') -module.exports = rule('remark-lint:no-duplicate-definitions', noDuplicateDefinitions); +module.exports = rule( + 'remark-lint:no-duplicate-definitions', + noDuplicateDefinitions +) -function noDuplicateDefinitions(ast, file) { - var map = {}; +var reason = 'Do not use definitions with the same identifier' - visit(ast, 'definition', validate); - visit(ast, 'footnoteDefinition', validate); +function noDuplicateDefinitions(tree, file) { + var map = {} + + visit(tree, ['definition', 'footnoteDefinition'], validate) function validate(node) { - var duplicate = map[node.identifier]; - var pos; + var identifier + var duplicate + var pos - if (generated(node)) { - return; - } + if (!generated(node)) { + identifier = node.identifier + duplicate = map[identifier] - if (duplicate && duplicate.type) { - pos = position.start(duplicate); + if (duplicate && duplicate.type) { + pos = position.start(duplicate) + file.message(reason + ' (' + pos.line + ':' + pos.column + ')', node) + } - file.message( - 'Do not use definitions with the same identifier (' + - pos.line + ':' + pos.column + ')', - node - ); + map[identifier] = node } - - map[node.identifier] = node; } } diff --git a/packages/remark-lint-no-duplicate-headings-in-section/index.js b/packages/remark-lint-no-duplicate-headings-in-section/index.js index bc5fde24..75677535 100644 --- a/packages/remark-lint-no-duplicate-headings-in-section/index.js +++ b/packages/remark-lint-no-duplicate-headings-in-section/index.js @@ -38,39 +38,40 @@ * 5:1-5:9: Do not use headings with similar content per section (3:1) */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); -var visit = require('unist-util-visit'); -var toString = require('mdast-util-to-string'); +var rule = require('unified-lint-rule') +var position = require('unist-util-position') +var generated = require('unist-util-generated') +var visit = require('unist-util-visit') +var toString = require('mdast-util-to-string') -module.exports = rule('remark-lint:no-duplicate-headings-in-section', noDuplicateHeadingsInSection); +module.exports = rule( + 'remark-lint:no-duplicate-headings-in-section', + noDuplicateHeadingsInSection +) + +var reason = 'Do not use headings with similar content per section' function noDuplicateHeadingsInSection(tree, file) { - var stack = [{}]; + var stack = [{}] - visit(tree, 'heading', visitor); + visit(tree, 'heading', visitor) function visitor(node) { - var depth = node.depth; - var siblings = stack[depth - 1] || {}; - var value = toString(node).toUpperCase(); - var duplicate = siblings[value]; - var pos; + var depth = node.depth + var siblings = stack[depth - 1] || {} + var value = toString(node).toUpperCase() + var duplicate = siblings[value] + var pos - stack = stack.slice(0, depth); - stack[depth] = {}; - siblings[value] = node; + stack = stack.slice(0, depth) + stack[depth] = {} + siblings[value] = node if (!generated(node) && duplicate && duplicate.type === 'heading') { - pos = position.start(duplicate); - file.message( - 'Do not use headings with similar content per section (' + - pos.line + ':' + pos.column + ')', - node - ); + pos = position.start(duplicate) + file.message(reason + ' (' + pos.line + ':' + pos.column + ')', node) } } } diff --git a/packages/remark-lint-no-duplicate-headings/index.js b/packages/remark-lint-no-duplicate-headings/index.js index d176c764..7a17d33c 100644 --- a/packages/remark-lint-no-duplicate-headings/index.js +++ b/packages/remark-lint-no-duplicate-headings/index.js @@ -26,40 +26,39 @@ * 5:1-5:29: Do not use headings with similar content (3:1) */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); -var visit = require('unist-util-visit'); -var toString = require('mdast-util-to-string'); +var rule = require('unified-lint-rule') +var position = require('unist-util-position') +var generated = require('unist-util-generated') +var visit = require('unist-util-visit') +var toString = require('mdast-util-to-string') -module.exports = rule('remark-lint:no-duplicate-headings', noDuplicateHeadings); +module.exports = rule('remark-lint:no-duplicate-headings', noDuplicateHeadings) -function noDuplicateHeadings(ast, file) { - var map = {}; +var reason = 'Do not use headings with similar content' - visit(ast, 'heading', visitor); +function noDuplicateHeadings(tree, file) { + var map = {} + + visit(tree, 'heading', visitor) function visitor(node) { - var value = toString(node).toUpperCase(); - var duplicate = map[value]; - var pos; + var value + var duplicate + var pos - if (generated(node)) { - return; - } + if (!generated(node)) { + value = toString(node).toUpperCase() + duplicate = map[value] - if (duplicate && duplicate.type === 'heading') { - pos = position.start(duplicate); + if (duplicate && duplicate.type === 'heading') { + pos = position.start(duplicate) - file.message( - 'Do not use headings with similar content (' + - pos.line + ':' + pos.column + ')', - node - ); - } + file.message(reason + ' (' + pos.line + ':' + pos.column + ')', node) + } - map[value] = node; + map[value] = node + } } } diff --git a/packages/remark-lint-no-emphasis-as-heading/index.js b/packages/remark-lint-no-emphasis-as-heading/index.js index d676459d..485c95e9 100644 --- a/packages/remark-lint-no-emphasis-as-heading/index.js +++ b/packages/remark-lint-no-emphasis-as-heading/index.js @@ -29,35 +29,33 @@ * 5:1-5:8: Don’t use emphasis to introduce a section, use a heading */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:no-emphasis-as-heading', noEmphasisAsHeading); +module.exports = rule('remark-lint:no-emphasis-as-heading', noEmphasisAsHeading) -function noEmphasisAsHeading(ast, file) { - visit(ast, 'paragraph', visitor); +var reason = 'Don’t use emphasis to introduce a section, use a heading' - function visitor(node, index, parent) { - var children = node.children; - var child = children[0]; - var prev = parent.children[index - 1]; - var next = parent.children[index + 1]; +function noEmphasisAsHeading(tree, file) { + visit(tree, 'paragraph', visitor) - if (generated(node)) { - return; - } + function visitor(node, index, parent) { + var head = node.children[0] + var prev = parent.children[index - 1] + var next = parent.children[index + 1] if ( + !generated(node) && (!prev || prev.type !== 'heading') && next && next.type === 'paragraph' && - children.length === 1 && - (child.type === 'emphasis' || child.type === 'strong') + node.children.length === 1 && + (head.type === 'emphasis' || head.type === 'strong') ) { - file.message('Don’t use emphasis to introduce a section, use a heading', node); + file.message(reason, node) } } } diff --git a/packages/remark-lint-no-empty-url/index.js b/packages/remark-lint-no-empty-url/index.js index 2ed3a6e3..402d9c19 100644 --- a/packages/remark-lint-no-empty-url/index.js +++ b/packages/remark-lint-no-empty-url/index.js @@ -11,7 +11,7 @@ * [alpha](http://bravo.com). * * ![charlie](http://delta.com/echo.png "foxtrott"). -* + * * @example {"name": "invalid.md", "label": "input"} * * [golf](). @@ -24,22 +24,20 @@ * 3:1-3:11: Don’t use images without URL */ -'use strict'; - -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var generated = require('unist-util-generated'); +'use strict' -module.exports = rule('remark-lint:no-empty-url', noEmptyURL); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var generated = require('unist-util-generated') -var types = ['link', 'image']; +module.exports = rule('remark-lint:no-empty-url', noEmptyURL) function noEmptyURL(tree, file) { - visit(tree, visitor); + visit(tree, ['link', 'image'], visitor) function visitor(node) { - if (types.indexOf(node.type) !== -1 && !generated(node) && !node.url) { - file.message('Don’t use ' + node.type + 's without URL', node); + if (!generated(node) && !node.url) { + file.message('Don’t use ' + node.type + 's without URL', node) } } } diff --git a/packages/remark-lint-no-file-name-articles/index.js b/packages/remark-lint-no-file-name-articles/index.js index 196cceb5..31ded716 100644 --- a/packages/remark-lint-no-file-name-articles/index.js +++ b/packages/remark-lint-no-file-name-articles/index.js @@ -25,16 +25,16 @@ * 1:1: Do not start file names with `an` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); +var rule = require('unified-lint-rule') -module.exports = rule('remark-lint:no-file-name-articles', noFileNameArticles); +module.exports = rule('remark-lint:no-file-name-articles', noFileNameArticles) -function noFileNameArticles(ast, file) { - var match = file.stem && file.stem.match(/^(the|teh|an?)\b/i); +function noFileNameArticles(tree, file) { + var match = file.stem && file.stem.match(/^(the|teh|an?)\b/i) if (match) { - file.message('Do not start file names with `' + match[0] + '`'); + file.message('Do not start file names with `' + match[0] + '`') } } diff --git a/packages/remark-lint-no-file-name-consecutive-dashes/index.js b/packages/remark-lint-no-file-name-consecutive-dashes/index.js index c76dd49d..30f7038d 100644 --- a/packages/remark-lint-no-file-name-consecutive-dashes/index.js +++ b/packages/remark-lint-no-file-name-consecutive-dashes/index.js @@ -13,14 +13,19 @@ * 1:1: Do not use consecutive dashes in a file name */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); +var rule = require('unified-lint-rule') -module.exports = rule('remark-lint:no-file-name-consecutive-dashes', noFileNameConsecutiveDashes); +module.exports = rule( + 'remark-lint:no-file-name-consecutive-dashes', + noFileNameConsecutiveDashes +) -function noFileNameConsecutiveDashes(ast, file) { +var reason = 'Do not use consecutive dashes in a file name' + +function noFileNameConsecutiveDashes(tree, file) { if (file.stem && /-{2,}/.test(file.stem)) { - file.message('Do not use consecutive dashes in a file name'); + file.message(reason) } } diff --git a/packages/remark-lint-no-file-name-irregular-characters/index.js b/packages/remark-lint-no-file-name-irregular-characters/index.js index b48c5244..9aec3c6a 100644 --- a/packages/remark-lint-no-file-name-irregular-characters/index.js +++ b/packages/remark-lint-no-file-name-irregular-characters/index.js @@ -31,23 +31,28 @@ * 1:1: Do not use ` ` in a file name */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); +var rule = require('unified-lint-rule') -module.exports = rule('remark-lint:no-file-name-irregular-characters', noFileNameIrregularCharacters); +module.exports = rule( + 'remark-lint:no-file-name-irregular-characters', + noFileNameIrregularCharacters +) -function noFileNameIrregularCharacters(ast, file, preferred) { - var expression = preferred || /[^\\.a-zA-Z0-9-]/; - var match; +var expression = /[^\\.a-zA-Z0-9-]/ - if (typeof expression === 'string') { - expression = new RegExp('[^' + expression + ']'); +function noFileNameIrregularCharacters(tree, file, pref) { + var style = pref || expression + var match + + if (typeof style === 'string') { + style = new RegExp('[^' + style + ']') } - match = file.stem && file.stem.match(expression); + match = file.stem && file.stem.match(style) if (match) { - file.message('Do not use `' + match[0] + '` in a file name'); + file.message('Do not use `' + match[0] + '` in a file name') } } diff --git a/packages/remark-lint-no-file-name-mixed-case/index.js b/packages/remark-lint-no-file-name-mixed-case/index.js index 74e51bd9..1916a67c 100644 --- a/packages/remark-lint-no-file-name-mixed-case/index.js +++ b/packages/remark-lint-no-file-name-mixed-case/index.js @@ -16,16 +16,21 @@ * 1:1: Do not mix casing in file names */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); +var rule = require('unified-lint-rule') -module.exports = rule('remark-lint:no-file-name-mixed-case', noFileNameMixedCase); +module.exports = rule( + 'remark-lint:no-file-name-mixed-case', + noFileNameMixedCase +) -function noFileNameMixedCase(ast, file) { - var name = file.stem; +var reason = 'Do not mix casing in file names' + +function noFileNameMixedCase(tree, file) { + var name = file.stem if (name && !(name === name.toLowerCase() || name === name.toUpperCase())) { - file.message('Do not mix casing in file names'); + file.message(reason) } } diff --git a/packages/remark-lint-no-file-name-outer-dashes/index.js b/packages/remark-lint-no-file-name-outer-dashes/index.js index eb2ed657..7cb318e4 100644 --- a/packages/remark-lint-no-file-name-outer-dashes/index.js +++ b/packages/remark-lint-no-file-name-outer-dashes/index.js @@ -17,14 +17,19 @@ * 1:1: Do not use initial or final dashes in a file name */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); +var rule = require('unified-lint-rule') -module.exports = rule('remark-lint:no-file-name-outer-dashes', noFileNameOuterDashes); +module.exports = rule( + 'remark-lint:no-file-name-outer-dashes', + noFileNameOuterDashes +) -function noFileNameOuterDashes(ast, file) { +var reason = 'Do not use initial or final dashes in a file name' + +function noFileNameOuterDashes(tree, file) { if (file.stem && /^-|-$/.test(file.stem)) { - file.message('Do not use initial or final dashes in a file name'); + file.message(reason) } } diff --git a/packages/remark-lint-no-heading-content-indent/index.js b/packages/remark-lint-no-heading-content-indent/index.js index 456541c5..c98aac44 100644 --- a/packages/remark-lint-no-heading-content-indent/index.js +++ b/packages/remark-lint-no-heading-content-indent/index.js @@ -57,75 +57,85 @@ * 3:34: Remove 1 space after this heading’s content */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var style = require('mdast-util-heading-style'); -var plural = require('plur'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var style = require('mdast-util-heading-style') +var plural = require('plur') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:no-heading-content-indent', noHeadingContentIndent); +module.exports = rule( + 'remark-lint:no-heading-content-indent', + noHeadingContentIndent +) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end -function noHeadingContentIndent(ast, file) { - var contents = file.toString(); +function noHeadingContentIndent(tree, file) { + var contents = String(file) - visit(ast, 'heading', visitor); + visit(tree, 'heading', visitor) function visitor(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; + var depth + var children + var type + var head + var initial + var final + var diff + var absDiff + var index + var char + var reason if (generated(node)) { - return; + return } + depth = node.depth + children = node.children + type = style(node, 'atx') + if (type === 'atx' || type === 'atx-closed') { - initial = start(node); - index = initial.offset; - char = contents.charAt(index); + initial = start(node) + index = initial.offset + char = contents.charAt(index) while (char && char !== '#') { - index++; - char = contents.charAt(index); + char = contents.charAt(++index) } /* istanbul ignore if - CR/LF bug: remarkjs/remark#195. */ if (!char) { - return; + return } - index = depth + (index - initial.offset); - head = start(children[0]).column; + index = depth + (index - initial.offset) + head = start(children[0]).column /* Ignore empty headings. */ if (!head) { - return; + return } - diff = head - initial.column - 1 - index; + diff = head - initial.column - 1 - index if (diff) { - word = diff > 0 ? 'Remove' : 'Add'; - diff = Math.abs(diff); - - file.message( - word + ' ' + diff + ' ' + plural('space', diff) + - ' before this heading’s content', - start(children[0]) - ); + absDiff = Math.abs(diff) + + reason = + (diff > 0 ? 'Remove' : 'Add') + + ' ' + + absDiff + + ' ' + + plural('space', absDiff) + + ' before this heading’s content' + + file.message(reason, start(children[0])) } } @@ -133,15 +143,18 @@ function noHeadingContentIndent(ast, file) { * 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; + final = end(children[children.length - 1]) + diff = end(node).column - final.column - 1 - depth if (diff) { - file.message( - 'Remove ' + diff + ' ' + plural('space', diff) + - ' after this heading’s content', - final - ); + reason = + 'Remove ' + + diff + + ' ' + + plural('space', diff) + + ' after this heading’s content' + + file.message(reason, final) } } } diff --git a/packages/remark-lint-no-heading-indent/index.js b/packages/remark-lint-no-heading-indent/index.js index 59211948..c9cba021 100644 --- a/packages/remark-lint-no-heading-indent/index.js +++ b/packages/remark-lint-no-heading-indent/index.js @@ -46,54 +46,57 @@ * 8:4: Remove 3 spaces before this heading */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var plural = require('plur'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var plural = require('plur') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:no-heading-indent', noHeadingIndent); +module.exports = rule('remark-lint:no-heading-indent', noHeadingIndent) -var start = position.start; +var start = position.start -function noHeadingIndent(ast, file) { - var contents = file.toString(); - var length = contents.length; +function noHeadingIndent(tree, file) { + var contents = String(file) + var length = contents.length - visit(ast, 'heading', visitor); + visit(tree, 'heading', visitor) function visitor(node) { - var initial = start(node); - var begin = initial.offset; - var index = begin - 1; - var character; - var diff; + var initial + var begin + var index + var character + var diff if (generated(node)) { - return; + return } + initial = start(node) + begin = initial.offset + index = begin - 1 + while (++index < length) { - character = contents.charAt(index); + character = contents.charAt(index) if (character !== ' ' && character !== '\t') { - break; + break } } - diff = index - begin; + diff = index - begin if (diff) { file.message( - 'Remove ' + diff + ' ' + plural('space', diff) + - ' before this heading', + 'Remove ' + diff + ' ' + plural('space', diff) + ' before this heading', { line: initial.line, column: initial.column + diff } - ); + ) } } } diff --git a/packages/remark-lint-no-heading-like-paragraph/index.js b/packages/remark-lint-no-heading-like-paragraph/index.js index 7601fcfa..a37287b5 100644 --- a/packages/remark-lint-no-heading-like-paragraph/index.js +++ b/packages/remark-lint-no-heading-like-paragraph/index.js @@ -23,29 +23,36 @@ * 1:1-1:16: This looks like a heading but has too many hashes */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:no-heading-like-paragraph', noHeadingLikeParagraph); +module.exports = rule( + 'remark-lint:no-heading-like-paragraph', + noHeadingLikeParagraph +) -var fence = '#######'; +var fence = '#######' +var reason = 'This looks like a heading but has too many hashes' function noHeadingLikeParagraph(tree, file) { - visit(tree, 'paragraph', visitor); + visit(tree, 'paragraph', visitor) function visitor(node) { - var head = node.children[0]; - - if ( - head && - head.type === 'text' && - head.value.slice(0, fence.length) === fence && - !generated(node) - ) { - file.message('This looks like a heading but has too many hashes', node); + var head + + if (!generated(node)) { + head = node.children[0] + + if ( + head && + head.type === 'text' && + head.value.slice(0, fence.length) === fence + ) { + file.message(reason, node) + } } } } diff --git a/packages/remark-lint-no-heading-punctuation/index.js b/packages/remark-lint-no-heading-punctuation/index.js index 88dd17a6..e3de758a 100644 --- a/packages/remark-lint-no-heading-punctuation/index.js +++ b/packages/remark-lint-no-heading-punctuation/index.js @@ -40,31 +40,37 @@ * 9:1-9:9: Don’t add a trailing `;` to headings */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var generated = require('unist-util-generated'); -var toString = require('mdast-util-to-string'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var generated = require('unist-util-generated') +var toString = require('mdast-util-to-string') -module.exports = rule('remark-lint:no-heading-punctuation', noHeadingPunctuation); +module.exports = rule( + 'remark-lint:no-heading-punctuation', + noHeadingPunctuation +) -function noHeadingPunctuation(ast, file, preferred) { - preferred = typeof preferred === 'string' ? preferred : '\\.,;:!?'; +var defaults = '\\.,;:!?' - visit(ast, 'heading', visitor); +function noHeadingPunctuation(tree, file, pref) { + var expression = new RegExp( + '[' + (typeof pref === 'string' ? pref : defaults) + ']' + ) - function visitor(node) { - var value = toString(node); + visit(tree, 'heading', visitor) - if (generated(node)) { - return; - } + function visitor(node) { + var value - value = value.charAt(value.length - 1); + if (!generated(node)) { + value = toString(node) + value = value.charAt(value.length - 1) - if (new RegExp('[' + preferred + ']').test(value)) { - file.message('Don’t add a trailing `' + value + '` to headings', node); + if (expression.test(value)) { + file.message('Don’t add a trailing `' + value + '` to headings', node) + } } } } diff --git a/packages/remark-lint-no-html/index.js b/packages/remark-lint-no-html/index.js index d0367f40..e6ee492b 100644 --- a/packages/remark-lint-no-html/index.js +++ b/packages/remark-lint-no-html/index.js @@ -24,20 +24,22 @@ * 1:1-1:15: Do not use HTML in markdown */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:no-html', noHTML); +module.exports = rule('remark-lint:no-html', noHTML) -function noHTML(ast, file) { - visit(ast, 'html', visitor); +var reason = 'Do not use HTML in markdown' + +function noHTML(tree, file) { + visit(tree, 'html', visitor) function visitor(node) { if (!generated(node) && !/^\s* * - * + * | | Alpha | Bravo| + * | ------ | ----- | ---: | + * | Charlie| | Echo| * - * | | Alpha | - * | ----- | ------- | - * | Bravo | Charlie | + * @example {"name": "empty.md", "label": "output", "setting": "padded"} * - * @example {"name": "empty-body.md"} + * 3:25: Cell should be padded + * 5:10: Cell should be padded + * 5:25: Cell should be padded * - * + * @example {"name": "missing-body.md", "setting": "padded"} * - * | Alpha | Bravo | - * | ------- | ------- | - * | Charlie | | + * + * + * | Alpha | Bravo | Charlie | + * | ----- | -------- | ------- | + * | Delta | + * | Echo | Foxtrott | */ -'use strict'; +'use strict' + +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +module.exports = rule('remark-lint:table-cell-padding', tableCellPadding) -module.exports = rule('remark-lint:table-cell-padding', tableCellPadding); +var start = position.start +var end = position.end -var start = position.start; -var end = position.end; +var styles = {null: true, padded: true, compact: true} -var STYLES = { - null: true, - padded: true, - compact: true -}; +function tableCellPadding(tree, file, pref) { + var contents = String(file) -function tableCellPadding(tree, file, preferred) { - preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; + pref = typeof pref === 'string' && pref !== 'consistent' ? pref : null - if (STYLES[preferred] !== true) { - file.fail('Invalid table-cell-padding style `' + preferred + '`'); + if (styles[pref] !== true) { + file.fail('Invalid table-cell-padding style `' + pref + '`') } - visit(tree, 'table', visitor); + visit(tree, 'table', visitor) function visitor(node) { - var rows = node.children; - var contents = String(file); - var starts = []; - var ends = []; - var cells = []; - var style; - var sizes; - - if (generated(node)) { - return; - } - - rows.forEach(eachRow); + var rows = node.children + var sizes = new Array(node.align.length) + var length = generated(node) ? -1 : rows.length + var index = -1 + var entries = [] + var style + var row + var cells + var column + var cellCount + var cell + var next + var fence + var pos + var entry + var final + + /* Check rows. */ + while (++index < length) { + row = rows[index] + cells = row.children + cellCount = cells.length + column = -2 /* Start without a first cell */ + next = null + final = undefined + + /* Check fences (before, between, and after cells) */ + while (++column < cellCount) { + cell = next + next = cells[column + 1] + + fence = contents.slice( + cell ? end(cell).offset : start(row).offset, + next ? start(next).offset : end(row).offset + ) + + pos = fence.indexOf('|') + + if (cell && cell.children.length !== 0 && final !== undefined) { + entries.push({node: cell, start: final, end: pos, index: column}) + + /* Detect max space per column. */ + sizes[column] = Math.max(sizes[column] || 0, size(cell)) + } else { + final = undefined + } - sizes = inferSizes(node); + if (next && next.children.length !== 0) { + final = fence.length - pos - 1 + } else { + final = undefined + } + } + } - if (preferred === 'padded') { - style = 1; - } else if (preferred === 'compact') { - style = 0; + if (pref) { + style = pref === 'padded' ? 1 : 0 } else { - style = null; - starts.concat(ends).some(inferStyle); + style = entries[0] && (!entries[0].start || !entries[0].end) ? 0 : 1 } - cells.forEach(checkCell); - - function eachRow(row) { - var children = row.children; - - check(start(row).offset, start(children[0]).offset, null, children[0]); - ends.pop(); /* Ignore end before row. */ - - children.forEach(eachCell); - starts.pop(); /* Ignore start after row */ + index = -1 + length = entries.length - function eachCell(cell, index) { - var next = children[index + 1] || null; - check(end(cell).offset, start(next).offset || end(row).offset, cell, next); - cells.push(cell); - } + while (++index < length) { + entry = entries[index] + checkSide('start', entry, style, sizes) + checkSide('end', entry, style, sizes) } - function inferStyle(pos) { - if (pos === undefined) { - return false; - } - - style = Math.min(pos, 1); - return true; - } + return visit.SKIP + } - function check(initial, final, prev, next) { - var fence = contents.slice(initial, final); - var pos = fence.indexOf('|'); + function checkSide(side, entry, style, sizes) { + var cell = entry.node + var spacing = entry[side] + var index = entry.index + var reason - ends.push(prev && pos !== -1 && prev.children.length !== 0 ? pos : undefined); - starts.push(next && next.children.length !== 0 ? fence.length - pos - 1 : undefined); + if (spacing === undefined || spacing === style) { + return } - function checkCell(cell, index) { - /* Ignore, when compact, every cell except the biggest in the column. */ - if (style === 0 && size(cell) < sizes[index % sizes.length]) { - return; - } - - checkSide('start', cell, starts[index], index); - checkSide('end', cell, ends[index]); - } + reason = 'Cell should be ' - function checkSide(side, cell, spacing, index) { - var message; + if (style === 0) { + reason += 'compact' - if (spacing === undefined || spacing === style) { - return; + /* Ignore every cell except the biggest in the column. */ + if (size(cell) < sizes[index]) { + return } + } else { + reason += 'padded' - message = 'Cell should be '; - - if (style === 0) { - message += 'compact'; - } else { - message += 'padded'; - - if (spacing > style) { - message += ' with 1 space, not ' + spacing; + if (spacing > style) { + reason += ' with 1 space, not ' + spacing - /* May be right or center aligned. */ - if (size(cell) < sizes[index % sizes.length]) { - return; - } + /* May be right or center aligned. */ + if (size(cell) < sizes[index]) { + return } } - - file.message(message, cell.position[side]); } - } -} - -function inferSizes(tree) { - var sizes = new Array(tree.align.length); - - tree.children.forEach(row); - - return sizes; - - function row(node) { - node.children.forEach(cell); - } - function cell(node, index) { - sizes[index] = Math.max(sizes[index] || 0, size(node)); + file.message(reason, cell.position[side]) } } function size(node) { - return end(node).offset - start(node).offset; + return end(node).offset - start(node).offset } diff --git a/packages/remark-lint-table-cell-padding/readme.md b/packages/remark-lint-table-cell-padding/readme.md index 2db5b35f..961eb9cc 100644 --- a/packages/remark-lint-table-cell-padding/readme.md +++ b/packages/remark-lint-table-cell-padding/readme.md @@ -56,6 +56,16 @@ When configured with `'padded'`. | A | B | | :----|----: | | Alpha|Bravo | + +| C | D | +| :----- | ---: | +|Charlie | Delta| + +Too much padding isn’t good either: + +| E | F | G | H | +| :---- | -------- | :----: | -----: | +| Echo | Foxtrot | Golf | Hotel | ``` ###### Out @@ -63,8 +73,53 @@ When configured with `'padded'`. ```text 3:8: Cell should be padded 3:9: Cell should be padded +7:2: Cell should be padded +7:17: Cell should be padded +13:23: Cell should be padded with 1 space, not 2 +13:32: Cell should be padded with 1 space, not 2 +``` + +##### `empty.md` + +When configured with `'padded'`. + +###### In + +```markdown + + +| | Alpha | Bravo| +| ------ | ----- | ---: | +| Charlie| | Echo| ``` +###### Out + +```text +3:25: Cell should be padded +5:10: Cell should be padded +5:25: Cell should be padded +``` + +##### `missing-body.md` + +When configured with `'padded'`. + +###### In + +```markdown + + +| Alpha | Bravo | Charlie | +| ----- | -------- | ------- | +| Delta | +| Echo | Foxtrott | +``` + +###### Out + +No messages. + ##### `valid.md` When configured with `'compact'`. @@ -88,66 +143,106 @@ When configured with `'compact'`. ###### In ```markdown -|A | B| -|:----|-----:| -|Alpha|Bravo | +| A | B | +| -----| -----| +| Alpha| Bravo| + +|C | D| +|:------|-----:| +|Charlie|Delta | ``` ###### Out ```text -3:13: Cell should be compact +3:5: Cell should be compact +3:12: Cell should be compact +7:15: Cell should be compact ``` -##### `invalid.md` +##### `valid-padded.md` + +When configured with `'consistent'`. ###### In ```markdown -| A | B | -| -----| -----| -| Alpha| Bravo| +| A | B | +| ----- | ----- | +| Alpha | Bravo | + +| C | D | +| ------- | ----- | +| Charlie | Delta | +``` + +###### Out + +No messages. + +##### `invalid-padded.md` + +When configured with `'consistent'`. + +###### In + +```markdown +| A | B | +| ----- | ----- | +| Alpha | Bravo | + +| C | D | +| :----- | ----: | +|Charlie | Delta | ``` ###### Out ```text -3:5: Cell should be padded with 1 space, not 3 -3:10: Cell should be padded -3:17: Cell should be padded +7:2: Cell should be padded ``` -##### `empty-heading.md` +##### `valid-compact.md` + +When configured with `'consistent'`. ###### In ```markdown - +|A |B | +|-----|-----| +|Alpha|Bravo| -| | Alpha | -| ----- | ------- | -| Bravo | Charlie | +|C |D | +|-------|-----| +|Charlie|Delta| ``` ###### Out No messages. -##### `empty-body.md` +##### `invalid-compact.md` + +When configured with `'consistent'`. ###### In ```markdown - +|A |B | +|-----|-----| +|Alpha|Bravo| -| Alpha | Bravo | -| ------- | ------- | -| Charlie | | +|C | D| +|:------|-----:| +|Charlie|Delta | ``` ###### Out -No messages. +```text +7:15: Cell should be compact +``` ##### `invalid.md` diff --git a/packages/remark-lint-table-pipe-alignment/index.js b/packages/remark-lint-table-pipe-alignment/index.js index a58e2165..463a8381 100644 --- a/packages/remark-lint-table-pipe-alignment/index.js +++ b/packages/remark-lint-table-pipe-alignment/index.js @@ -41,62 +41,69 @@ * 3:17-3:18: Misaligned table fence */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:table-pipe-alignment', tablePipeAlignment); +module.exports = rule('remark-lint:table-pipe-alignment', tablePipeAlignment) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end -function tablePipeAlignment(ast, file) { - visit(ast, 'table', visitor); +var reason = 'Misaligned table fence' - function visitor(node) { - var contents = file.toString(); - var indices = []; - var offset; - var line; - - if (generated(node)) { - return; - } - - node.children.forEach(visitRow); - - function visitRow(row) { - var cells = row.children; - - line = start(row).line; - offset = start(row).offset; - - check(start(row).offset, start(cells[0]).offset, 0); +function tablePipeAlignment(tree, file) { + var contents = String(file) - row.children.forEach(visitCell); + visit(tree, 'table', visitor) - function visitCell(cell, index) { - var next = start(cells[index + 1]).offset || end(row).offset; - - check(end(cell).offset, next, index + 1); - } - } - - /* Check that all pipes after each column are at - * aligned. */ - function check(initial, final, index) { - var pos = initial + contents.slice(initial, final).indexOf('|') - offset + 1; - - if (indices[index] === undefined || indices[index] === null) { - indices[index] = pos; - } else if (pos !== indices[index]) { - file.message('Misaligned table fence', { - start: {line: line, column: pos}, - end: {line: line, column: pos + 1} - }); + function visitor(node) { + var rows = node.children + var length = generated(node) ? 0 : rows.length + var index = -1 + var indices = [] + var row + var cells + var begin + var column + var columns + var cell + var initial + var final + var next + var nextIndex + var fence + var pos + + while (++index < length) { + row = rows[index] + begin = start(row) + cells = row.children + columns = cells.length + column = -2 /* Start without a first cell */ + next = null + + while (++column < columns) { + cell = next + nextIndex = column + 1 + next = cells[nextIndex] + + initial = cell ? end(cell).offset : start(row).offset + final = next ? start(next).offset : end(row).offset + fence = contents.slice(initial, final) + pos = initial + fence.indexOf('|') - begin.offset + 1 + + if (indices[nextIndex] === undefined || indices[nextIndex] === null) { + indices[nextIndex] = pos + } else if (pos !== indices[nextIndex]) { + file.message(reason, { + start: {line: begin.line, column: pos}, + end: {line: begin.line, column: pos + 1} + }) + } } } } diff --git a/packages/remark-lint-table-pipes/index.js b/packages/remark-lint-table-pipes/index.js index f2106ac3..14441db8 100644 --- a/packages/remark-lint-table-pipes/index.js +++ b/packages/remark-lint-table-pipes/index.js @@ -36,43 +36,54 @@ * 3:14: Missing final pipe in table fence */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:table-pipes', tablePipes); +module.exports = rule('remark-lint:table-pipes', tablePipes) -var start = position.start; -var end = position.end; +var start = position.start +var end = position.end -function tablePipes(ast, file) { - visit(ast, 'table', visitor); +var reasonStart = 'Missing initial pipe in table fence' +var reasonEnd = 'Missing final pipe in table fence' - function visitor(node) { - var contents = file.toString(); +function tablePipes(tree, file) { + var contents = String(file) - node.children.forEach(visitRow); + visit(tree, 'table', visitor) - function visitRow(row) { - var cells = row.children; - var head = cells[0]; - var tail = cells[cells.length - 1]; - var initial = contents.slice(start(row).offset, start(head).offset); - var final = contents.slice(end(tail).offset, end(row).offset); + function visitor(node) { + var rows = node.children + var length = rows.length + var index = -1 + var row + var cells + var head + var tail + var initial + var final - if (generated(row)) { - return; - } + while (++index < length) { + row = rows[index] - if (initial.indexOf('|') === -1) { - file.message('Missing initial pipe in table fence', start(row)); - } + if (!generated(row)) { + cells = row.children + head = cells[0] + tail = cells[cells.length - 1] + initial = contents.slice(start(row).offset, start(head).offset) + final = contents.slice(end(tail).offset, end(row).offset) + + if (initial.indexOf('|') === -1) { + file.message(reasonStart, start(row)) + } - if (final.indexOf('|') === -1) { - file.message('Missing final pipe in table fence', end(row)); + if (final.indexOf('|') === -1) { + file.message(reasonEnd, end(row)) + } } } } diff --git a/packages/remark-lint-unordered-list-marker-style/index.js b/packages/remark-lint-unordered-list-marker-style/index.js index c41a3275..e03f54d5 100644 --- a/packages/remark-lint-unordered-list-marker-style/index.js +++ b/packages/remark-lint-unordered-list-marker-style/index.js @@ -65,63 +65,65 @@ * 1:1: Invalid unordered list-item marker style `!`: use either `'-'`, `'*'`, or `'+'` */ -'use strict'; +'use strict' -var rule = require('unified-lint-rule'); -var visit = require('unist-util-visit'); -var position = require('unist-util-position'); -var generated = require('unist-util-generated'); +var rule = require('unified-lint-rule') +var visit = require('unist-util-visit') +var position = require('unist-util-position') +var generated = require('unist-util-generated') -module.exports = rule('remark-lint:unordered-list-marker-style', unorderedListMarkerStyle); +module.exports = rule( + 'remark-lint:unordered-list-marker-style', + unorderedListMarkerStyle +) -var start = position.start; +var start = position.start -var STYLES = { +var styles = { '-': true, '*': true, '+': true, null: true -}; +} -function unorderedListMarkerStyle(ast, file, preferred) { - var contents = file.toString(); +function unorderedListMarkerStyle(tree, file, pref) { + var contents = String(file) - preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred; + pref = typeof pref === 'string' && pref !== 'consistent' ? pref : null - if (STYLES[preferred] !== true) { - file.fail('Invalid unordered list-item marker style `' + preferred + '`: use either `\'-\'`, `\'*\'`, or `\'+\'`'); + if (styles[pref] !== true) { + file.fail( + 'Invalid unordered list-item marker style `' + + pref + + "`: use either `'-'`, `'*'`, or `'+'`" + ) } - visit(ast, 'list', visitor); + visit(tree, 'list', visitor) function visitor(node) { - var items = node.children; - - if (node.ordered) { - return; - } - - items.forEach(visitItem); - - function visitItem(item) { - var head = item.children[0]; - var initial = start(item).offset; - var final = start(head).offset; - var marker; - - if (generated(item)) { - return; - } - - marker = contents.slice(initial, final).replace(/\s/g, ''); - - /* Support checkboxes. */ - marker = marker.replace(/\[[x ]?]\s*$/i, ''); - - if (!preferred) { - preferred = marker; - } else if (marker !== preferred) { - file.message('Marker style should be `' + preferred + '`', item); + var children = node.children + var length = node.ordered ? 0 : children.length + var index = -1 + var child + var marker + + while (++index < length) { + child = children[index] + + if (!generated(child)) { + marker = contents + .slice(start(child).offset, start(child.children[0]).offset) + .replace(/\[[x ]?]\s*$/i, '') + .replace(/\s/g, '') + + if (pref) { + if (marker !== pref) { + file.message('Marker style should be `' + pref + '`', child) + } + } else { + pref = marker + } } } } diff --git a/packages/remark-lint/index.js b/packages/remark-lint/index.js index d109b93b..e26876db 100644 --- a/packages/remark-lint/index.js +++ b/packages/remark-lint/index.js @@ -1,16 +1,16 @@ -'use strict'; +'use strict' -var control = require('remark-message-control'); +var control = require('remark-message-control') -module.exports = lint; +module.exports = lint /* `remark-lint`. This adds support for ignoring stuff from * messages (``). * All rules are in their own packages and presets. */ function lint() { - this.use(lintMessageControl); + this.use(lintMessageControl) } function lintMessageControl() { - return control({name: 'lint', source: 'remark-lint'}); + return control({name: 'lint', source: 'remark-lint'}) } diff --git a/packages/remark-preset-lint-consistent/index.js b/packages/remark-preset-lint-consistent/index.js index ce45adfb..f5f656da 100644 --- a/packages/remark-preset-lint-consistent/index.js +++ b/packages/remark-preset-lint-consistent/index.js @@ -4,7 +4,7 @@ * settings that enforce consistency. */ -'use strict'; +'use strict' module.exports.plugins = [ require('remark-lint'), @@ -20,4 +20,4 @@ module.exports.plugins = [ [require('remark-lint-rule-style'), 'consistent'], [require('remark-lint-strong-marker'), 'consistent'], [require('remark-lint-table-cell-padding'), 'consistent'] -]; +] diff --git a/packages/remark-preset-lint-markdown-style-guide/index.js b/packages/remark-preset-lint-markdown-style-guide/index.js index 63ee8088..1862153f 100644 --- a/packages/remark-preset-lint-markdown-style-guide/index.js +++ b/packages/remark-preset-lint-markdown-style-guide/index.js @@ -90,7 +90,7 @@ * ``` */ -'use strict'; +'use strict' module.exports.plugins = [ require('remark-lint'), @@ -232,4 +232,4 @@ module.exports.plugins = [ /* http://www.cirosantilli.com/markdown-style-guide/#email-automatic-links. * Not checked. */ -]; +] diff --git a/packages/remark-preset-lint-recommended/index.js b/packages/remark-preset-lint-recommended/index.js index caeeda40..9ccb50f7 100644 --- a/packages/remark-preset-lint-recommended/index.js +++ b/packages/remark-preset-lint-recommended/index.js @@ -5,7 +5,7 @@ * across vendors. */ -'use strict'; +'use strict' module.exports.plugins = [ require('remark-lint'), @@ -29,4 +29,4 @@ module.exports.plugins = [ require('remark-lint-no-shortcut-reference-link'), require('remark-lint-no-undefined-references'), require('remark-lint-no-unused-definitions') -]; +] diff --git a/packages/unified-lint-rule/index.js b/packages/unified-lint-rule/index.js index d24a79fe..b3c515e7 100644 --- a/packages/unified-lint-rule/index.js +++ b/packages/unified-lint-rule/index.js @@ -1,60 +1,60 @@ -'use strict'; +'use strict' -var wrapped = require('wrapped'); +var wrapped = require('wrapped') -module.exports = factory; +module.exports = factory function factory(id, rule) { - var parts = id.split(':'); - var source = parts[0]; - var ruleId = parts[1]; - var fn = wrapped(rule); + var parts = id.split(':') + var source = parts[0] + var ruleId = parts[1] + var fn = wrapped(rule) /* istanbul ignore if - possibly useful if externalised later. */ if (!ruleId) { - ruleId = source; - source = null; + ruleId = source + source = null } - attacher.displayName = id; + attacher.displayName = id - return attacher; + return attacher function attacher(raw) { - var config = coerce(ruleId, raw); - var severity = config[0]; - var options = config[1]; - var fatal = severity === 2; + var config = coerce(ruleId, raw) + var severity = config[0] + var options = config[1] + var fatal = severity === 2 - return severity ? transformer : undefined; + return severity ? transformer : undefined function transformer(tree, file, next) { - var index = file.messages.length; + var index = file.messages.length - fn(tree, file, options, done); + fn(tree, file, options, done) function done(err) { - var messages = file.messages; - var message; + var messages = file.messages + var message /* Add the error, if not already properly added. */ /* istanbul ignore if - only happens for incorrect plugins */ if (err && messages.indexOf(err) === -1) { try { - file.fail(err); + file.fail(err) } catch (err) {} } while (index < messages.length) { - message = messages[index]; - message.ruleId = ruleId; - message.source = source; - message.fatal = fatal; + message = messages[index] + message.ruleId = ruleId + message.source = source + message.fatal = fatal - index++; + index++ } - next(); + next() } } } @@ -62,53 +62,55 @@ function factory(id, rule) { /* Coerce a value to a severity--options tuple. */ function coerce(name, value) { - var def = 1; - var result; - var level; + var def = 1 + var result + var level /* istanbul ignore if - Handled by unified in v6.0.0 */ if (typeof value === 'boolean') { - result = [value]; + result = [value] } else if (value == null) { - result = [def]; + result = [def] } else if ( typeof value === 'object' && - ( - typeof value[0] === 'number' || + (typeof value[0] === 'number' || typeof value[0] === 'boolean' || - typeof value[0] === 'string' - ) + typeof value[0] === 'string') ) { - result = value.concat(); + result = value.concat() } else { - result = [1, value]; + result = [1, value] } - level = result[0]; + level = result[0] if (typeof level === 'boolean') { - level = level ? 1 : 0; + level = level ? 1 : 0 } else if (typeof level === 'string') { if (level === 'off') { - level = 0; + level = 0 } else if (level === 'on' || level === 'warn') { - level = 1; + level = 1 } else if (level === 'error') { - level = 2; + level = 2 } else { - level = 1; - result = [level, result]; + level = 1 + result = [level, result] } } if (level < 0 || level > 2) { throw new Error( - 'Invalid severity `' + level + '` for `' + name + '`, ' + - 'expected 0, 1, or 2' - ); + 'Invalid severity `' + + level + + '` for `' + + name + + '`, ' + + 'expected 0, 1, or 2' + ) } - result[0] = level; + result[0] = level - return result; + return result } diff --git a/script/build-presets.js b/script/build-presets.js index 45bae1c0..3cab0735 100644 --- a/script/build-presets.js +++ b/script/build-presets.js @@ -1,62 +1,74 @@ -'use strict'; +'use strict' -var fs = require('fs'); -var path = require('path'); -var u = require('unist-builder'); -var dox = require('dox'); -var chalk = require('chalk'); -var remark = require('remark'); -var strip = require('strip-indent'); -var trim = require('trim'); -var parseAuthor = require('parse-author'); -var remote = require('../package.json').repository; -var find = require('./util/find'); -var presets = require('./util/presets'); +var fs = require('fs') +var path = require('path') +var u = require('unist-builder') +var dox = require('dox') +var chalk = require('chalk') +var remark = require('remark') +var strip = require('strip-indent') +var trim = require('trim') +var parseAuthor = require('parse-author') +var remote = require('../package.json').repository +var find = require('./util/find') +var presets = require('./util/presets') -var root = path.join(process.cwd(), 'packages'); +var root = path.join(process.cwd(), 'packages') -presets(root).forEach(function (basename) { - var base = path.resolve(root, basename); - var pack = require(path.join(base, 'package.json')); - var doc = fs.readFileSync(path.join(base, 'index.js'), 'utf8'); - var tags = dox.parseComments(doc)[0].tags; - var author = parseAuthor(pack.author); - var description = trim(strip(find(tags, 'fileoverview'))); - var rows = []; - var children; - var short = basename.replace(/^remark-/, ''); +presets(root).forEach(function(basename) { + var base = path.resolve(root, basename) + var pack = require(path.join(base, 'package.json')) + var doc = fs.readFileSync(path.join(base, 'index.js'), 'utf8') + var tags = dox.parseComments(doc)[0].tags + var author = parseAuthor(pack.author) + var description = trim(strip(find(tags, 'fileoverview'))) + var rows = [] + var children + var short = basename.replace(/^remark-/, '') if (basename !== pack.name) { throw new Error( - 'Expected package name (`' + pack.name + '`) to be the same as ' + - 'directory name (`' + basename + '`)' - ); + 'Expected package name (`' + + pack.name + + '`) to be the same as ' + + 'directory name (`' + + basename + + '`)' + ) } - rows.push(u('tableRow', [ - u('tableCell', [u('text', 'Rule')]), - u('tableCell', [u('text', 'Setting')]) - ])); + rows.push( + u('tableRow', [ + u('tableCell', [u('text', 'Rule')]), + u('tableCell', [u('text', 'Setting')]) + ]) + ) - doc.replace(/require\('remark-lint-([^']+)'\)(?:, ([^\]]+)])?/g, function ($0, rule, option) { - var url = remote + '/tree/master/packages/remark-lint-' + rule; + doc.replace(/require\('remark-lint-([^']+)'\)(?:, ([^\]]+)])?/g, function( + $0, + rule, + option + ) { + var url = remote + '/tree/master/packages/remark-lint-' + rule - rows.push(u('tableRow', [ - u('tableCell', [ - u('link', {url: url, title: null}, [u('inlineCode', rule)]) - ]), - u('tableCell', option ? [u('inlineCode', option)] : []) - ])); + rows.push( + u('tableRow', [ + u('tableCell', [ + u('link', {url: url, title: null}, [u('inlineCode', rule)]) + ]), + u('tableCell', option ? [u('inlineCode', option)] : []) + ]) + ) - return ''; - }); + return '' + }) children = [ u('html', ''), u('heading', {depth: 1}, [u('text', basename)]) - ]; + ] - children = children.concat(remark().parse(description).children); + children = children.concat(remark().parse(description).children) children.push( u('heading', {depth: 2}, [u('text', 'Rules')]), @@ -70,39 +82,51 @@ presets(root).forEach(function (basename) { u('paragraph', [u('text', 'npm:')]), u('code', {lang: 'sh'}, 'npm install ' + basename), u('heading', {depth: 2}, [u('text', 'Usage')]), - u('paragraph', [u('text', 'You probably want to use it on the CLI through a config file:')]), - u('code', {lang: 'diff'}, [ - ' ...', - ' "remarkConfig": {', - '+ "plugins": ["' + short + '"]', - ' }', - ' ...' - ].join('\n')), + u('paragraph', [ + u('text', 'You probably want to use it on the CLI through a config file:') + ]), + u( + 'code', + {lang: 'diff'}, + [ + ' ...', + ' "remarkConfig": {', + '+ "plugins": ["' + short + '"]', + ' }', + ' ...' + ].join('\n') + ), u('paragraph', [u('text', 'Or use it on the CLI directly')]), u('code', {lang: 'sh'}, 'remark -u ' + short + ' readme.md'), u('paragraph', [u('text', 'Or use this on the API:')]), - u('code', {lang: 'diff'}, [ - ' var remark = require(\'remark\');', - ' var report = require(\'vfile-reporter\');', - '', - ' remark()', - '+ .use(require(\'' + basename + '\'))', - ' .process(\'_Emphasis_ and **importance**\', function (err, file) {', - ' console.error(report(err || file));', - ' });' - ].join('\n')), + u( + 'code', + {lang: 'diff'}, + [ + " var remark = require('remark');", + " var report = require('vfile-reporter');", + '', + ' remark()', + "+ .use(require('" + basename + "'))", + " .process('_Emphasis_ and **importance**', function (err, file) {", + ' console.error(report(err || file));', + ' });' + ].join('\n') + ), u('heading', {depth: 2}, [u('text', 'License')]), u('paragraph', [ - u('link', {url: remote + '/blob/master/LICENSE'}, [u('text', pack.license)]), + u('link', {url: remote + '/blob/master/LICENSE'}, [ + u('text', pack.license) + ]), u('text', ' © '), u('link', {url: author.url}, [u('text', author.name)]) ]) - ); + ) fs.writeFileSync( path.join(base, 'readme.md'), remark().stringify(u('root', children)) - ); + ) - console.log(chalk.green('✓') + ' wrote `readme.md` in `' + basename + '`'); -}); + console.log(chalk.green('✓') + ' wrote `readme.md` in `' + basename + '`') +}) diff --git a/script/build-rules.js b/script/build-rules.js index 0ca12c48..0ec958fc 100644 --- a/script/build-rules.js +++ b/script/build-rules.js @@ -1,100 +1,120 @@ -'use strict'; - -var fs = require('fs'); -var path = require('path'); -var inspect = require('util').inspect; -var u = require('unist-builder'); -var chalk = require('chalk'); -var remark = require('remark'); -var parseAuthor = require('parse-author'); -var remote = require('../package.json').repository; -var rules = require('./util/rules'); -var rule = require('./util/rule'); -var presets = require('./util/presets'); -var chars = require('./characters'); - -var root = path.join(process.cwd(), 'packages'); - -presets = presets(root).map(function (name) { - var doc = fs.readFileSync(path.join(root, name, 'index.js'), 'utf8'); - var packages = {}; - - doc.replace(/require\('(remark-lint-[^']+)'\)(?:, ([^\]]+)])?/g, function ($0, rule, option) { - packages[rule] = option || null; - return ''; - }); +'use strict' + +var fs = require('fs') +var path = require('path') +var inspect = require('util').inspect +var u = require('unist-builder') +var chalk = require('chalk') +var remark = require('remark') +var parseAuthor = require('parse-author') +var remote = require('../package.json').repository +var rules = require('./util/rules') +var rule = require('./util/rule') +var presets = require('./util/presets') +var chars = require('./characters') + +var root = path.join(process.cwd(), 'packages') + +presets = presets(root).map(function(name) { + var doc = fs.readFileSync(path.join(root, name, 'index.js'), 'utf8') + var packages = {} + + doc.replace(/require\('(remark-lint-[^']+)'\)(?:, ([^\]]+)])?/g, function( + $0, + rule, + option + ) { + packages[rule] = option || null + return '' + }) return { name: name, packages: packages - }; -}); - -rules(root).forEach(function (basename) { - var base = path.resolve(root, basename); - var pack = require(path.join(base, 'package.json')); - var info = rule(base); - var tests = info.tests; - var author = parseAuthor(pack.author); - var short = basename.replace(/^remark-/, ''); - var includes; + } +}) + +rules(root).forEach(function(basename) { + var base = path.resolve(root, basename) + var pack = require(path.join(base, 'package.json')) + var info = rule(base) + var tests = info.tests + var author = parseAuthor(pack.author) + var short = basename.replace(/^remark-/, '') + var includes var children = [ u('html', ''), u('heading', {depth: 1}, [u('text', basename)]) - ].concat(remark().parse(info.description).children); + ].concat(remark().parse(info.description).children) if (basename !== pack.name) { throw new Error( - 'Expected package name (`' + pack.name + '`) to be the same as ' + - 'directory name (`' + basename + '`)' - ); + 'Expected package name (`' + + pack.name + + '`) to be the same as ' + + 'directory name (`' + + basename + + '`)' + ) } - includes = presets.filter(function (preset) { - return basename in preset.packages; - }); + includes = presets.filter(function(preset) { + return basename in preset.packages + }) - children.push(u('heading', {depth: 2}, [u('text', 'Presets')])); + children.push(u('heading', {depth: 2}, [u('text', 'Presets')])) if (includes.length === 0) { - children.push(u('paragraph', [ - u('text', 'This rule is not included in any default preset') - ])); + children.push( + u('paragraph', [ + u('text', 'This rule is not included in any default preset') + ]) + ) } else { children.push( - u('paragraph', [u('text', 'This rule is included in the following presets:')]), - u('table', {align: []}, [ - u('tableRow', [ - u('tableCell', [u('text', 'Preset')]), - u('tableCell', [u('text', 'Setting')]) - ]) - ].concat(includes.map(function (preset) { - var url = remote + '/tree/master/packages/' + preset.name; - var option = preset.packages[pack.name]; - - return u('tableRow', [ - u('tableCell', [ - u('link', {url: url, title: null}, [u('inlineCode', preset.name)]) - ]), - u('tableCell', option ? [u('inlineCode', option)] : []) - ]); - }))) - ); + u('paragraph', [ + u('text', 'This rule is included in the following presets:') + ]), + u( + 'table', + {align: []}, + [ + u('tableRow', [ + u('tableCell', [u('text', 'Preset')]), + u('tableCell', [u('text', 'Setting')]) + ]) + ].concat( + includes.map(function(preset) { + var url = remote + '/tree/master/packages/' + preset.name + var option = preset.packages[pack.name] + + return u('tableRow', [ + u('tableCell', [ + u('link', {url: url, title: null}, [ + u('inlineCode', preset.name) + ]) + ]), + u('tableCell', option ? [u('inlineCode', option)] : []) + ]) + }) + ) + ) + ) } - Object.keys(tests).forEach(function (setting, index) { - var fixtures = tests[setting]; + Object.keys(tests).forEach(function(setting, index) { + var fixtures = tests[setting] if (index === 0) { - children.push(u('heading', {depth: 2}, [u('text', 'Example')])); + children.push(u('heading', {depth: 2}, [u('text', 'Example')])) } - Object.keys(fixtures).forEach(function (fileName) { - var fixture = fixtures[fileName]; - var label = inspect(JSON.parse(setting)); - var clean = fixture.input; + Object.keys(fixtures).forEach(function(fileName) { + var fixture = fixtures[fileName] + var label = inspect(JSON.parse(setting)) + var clean = fixture.input - children.push(u('heading', {depth: 5}, [u('inlineCode', fileName)])); + children.push(u('heading', {depth: 5}, [u('inlineCode', fileName)])) if (label !== 'true') { children.push( @@ -103,84 +123,96 @@ rules(root).forEach(function (basename) { u('inlineCode', label), u('text', '.') ]) - ); + ) } if (fixture.input != null && fixture.input.trim() !== '') { - children.push(u('heading', {depth: 6}, [u('text', 'In')])); + children.push(u('heading', {depth: 6}, [u('text', 'In')])) - chars.forEach(function (char) { - var next = clean.replace(char.in, char.out); + chars.forEach(function(char) { + var next = clean.replace(char.in, char.out) if (clean !== next) { - children.push(u('paragraph', [ - u('text', 'Note: '), - u('inlineCode', char.char), - u('text', ' represents ' + char.name + '.') - ])); - - clean = next; + children.push( + u('paragraph', [ + u('text', 'Note: '), + u('inlineCode', char.char), + u('text', ' represents ' + char.name + '.') + ]) + ) + + clean = next } - }); + }) - children.push(u('code', {lang: 'markdown'}, fixture.input)); + children.push(u('code', {lang: 'markdown'}, fixture.input)) } - children.push(u('heading', {depth: 6}, [u('text', 'Out')])); + children.push(u('heading', {depth: 6}, [u('text', 'Out')])) if (fixture.output.length === 0) { - children.push(u('paragraph', [u('text', 'No messages.')])); + children.push(u('paragraph', [u('text', 'No messages.')])) } else { - children.push(u('code', {lang: 'text'}, fixture.output.join('\n'))); + children.push(u('code', {lang: 'text'}, fixture.output.join('\n'))) } - }); - }); + }) + }) children = children.concat([ u('heading', {depth: 2}, [u('text', 'Install')]), u('code', {lang: 'sh'}, 'npm install ' + basename), u('heading', {depth: 2}, [u('text', 'Usage')]), - u('paragraph', [u('text', 'You probably want to use it on the CLI through a config file:')]), - u('code', {lang: 'diff'}, [ - ' ...', - ' "remarkConfig": {', - ' "plugins": [', - ' ...', - ' "lint",', - '+ "' + short + '",', - ' ...', - ' ]', - ' }', - ' ...' - ].join('\n')), + u('paragraph', [ + u('text', 'You probably want to use it on the CLI through a config file:') + ]), + u( + 'code', + {lang: 'diff'}, + [ + ' ...', + ' "remarkConfig": {', + ' "plugins": [', + ' ...', + ' "lint",', + '+ "' + short + '",', + ' ...', + ' ]', + ' }', + ' ...' + ].join('\n') + ), u('paragraph', [u('text', 'Or use it on the CLI directly')]), u('code', {lang: 'sh'}, 'remark -u lint -u ' + short + ' readme.md'), u('paragraph', [u('text', 'Or use this on the API:')]), - u('code', {lang: 'diff'}, [ - ' var remark = require(\'remark\');', - ' var report = require(\'vfile-reporter\');', - '', - ' remark()', - ' .use(require(\'remark-lint\'))', - '+ .use(require(\'' + basename + '\'))', - ' .process(\'_Emphasis_ and **importance**\', function (err, file) {', - ' console.error(report(err || file));', - ' });' - ].join('\n')), + u( + 'code', + {lang: 'diff'}, + [ + " var remark = require('remark');", + " var report = require('vfile-reporter');", + '', + ' remark()', + " .use(require('remark-lint'))", + "+ .use(require('" + basename + "'))", + " .process('_Emphasis_ and **importance**', function (err, file) {", + ' console.error(report(err || file));', + ' });' + ].join('\n') + ), u('heading', {depth: 2}, [u('text', 'License')]), u('paragraph', [ - u('link', {url: remote + '/blob/master/LICENSE'}, [u('text', pack.license)]), + u('link', {url: remote + '/blob/master/LICENSE'}, [ + u('text', pack.license) + ]), u('text', ' © '), u('link', {url: author.url}, [u('text', author.name)]) ]) - ]); + ]) fs.writeFileSync( path.join(base, 'readme.md'), remark().stringify(u('root', children)) - ); + ) - console.log( - chalk.green('✓') + ' wrote `readme.md` in `' + basename + '`' - ); -}); + console.log(chalk.green('✓') + ' wrote `readme.md` in `' + basename + '`') +}) diff --git a/script/characters.js b/script/characters.js index e0f807c8..b0ca9335 100644 --- a/script/characters.js +++ b/script/characters.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict' module.exports = [ { @@ -25,4 +25,4 @@ module.exports = [ out: '\n', char: '␊' } -]; +] diff --git a/script/plugin/list-of-presets.js b/script/plugin/list-of-presets.js index 9286d202..0d4f9adc 100644 --- a/script/plugin/list-of-presets.js +++ b/script/plugin/list-of-presets.js @@ -1,34 +1,37 @@ -'use strict'; +'use strict' -var path = require('path'); -var zone = require('mdast-zone'); -var u = require('unist-builder'); -var presets = require('../util/presets'); +var path = require('path') +var zone = require('mdast-zone') +var u = require('unist-builder') +var presets = require('../util/presets') -var root = path.join(process.cwd(), 'packages'); +var root = path.join(process.cwd(), 'packages') -module.exports = listOfPresets; +module.exports = listOfPresets function listOfPresets() { - return transformer; + return transformer } function transformer(tree) { - zone(tree, 'presets', replace); + zone(tree, 'presets', replace) } function replace(start, nodes, end) { - var items = presets(root).map(function (basename) { - var pack = require(path.join(root, basename, 'package.json')); - var description = pack.description.replace(/^remark preset to configure remark-lint with ?/i, ''); + return [start, u('list', {ordered: false}, presets(root).map(item)), end] + + function item(basename) { + var pack = require(path.join(root, basename, 'package.json')) + var description = pack.description.replace( + /^remark preset to configure remark-lint with ?/i, + '' + ) return u('listItem', [ u('paragraph', [ u('link', {url: pack.repository}, [u('inlineCode', basename)]), u('text', ' — ' + description) ]) - ]); - }); - - return [start, u('list', {ordered: false}, items), end]; + ]) + } } diff --git a/script/plugin/list-of-rules.js b/script/plugin/list-of-rules.js index 89c5b2c6..e9380612 100644 --- a/script/plugin/list-of-rules.js +++ b/script/plugin/list-of-rules.js @@ -1,35 +1,35 @@ -'use strict'; +'use strict' -var path = require('path'); -var zone = require('mdast-zone'); -var u = require('unist-builder'); -var rules = require('../util/rules'); +var path = require('path') +var zone = require('mdast-zone') +var u = require('unist-builder') +var rules = require('../util/rules') -var root = path.join(process.cwd(), 'packages'); +var root = path.join(process.cwd(), 'packages') -module.exports = listOfRules; +module.exports = listOfRules function listOfRules() { - return transformer; + return transformer } function transformer(tree) { - zone(tree, 'rules', replace); + zone(tree, 'rules', replace) } function replace(start, nodes, end) { - var items = rules(root).map(function (basename) { - var name = basename.slice('remark-lint-'.length); - var pack = require(path.join(root, basename, 'package.json')); - var description = pack.description.replace(/^remark-lint rule to ?/i, ''); + return [start, u('list', {ordered: false}, rules(root).map(item)), end] + + function item(basename) { + var name = basename.slice('remark-lint-'.length) + var pack = require(path.join(root, basename, 'package.json')) + var description = pack.description.replace(/^remark-lint rule to ?/i, '') return u('listItem', [ u('paragraph', [ u('link', {url: pack.repository}, [u('inlineCode', name)]), u('text', ' — ' + description) ]) - ]); - }); - - return [start, u('list', {ordered: false}, items), end]; + ]) + } } diff --git a/script/util/find.js b/script/util/find.js index 0b41c233..4cd99386 100755 --- a/script/util/find.js +++ b/script/util/find.js @@ -1,33 +1,33 @@ -'use strict'; +'use strict' -module.exports = find; +module.exports = find -find.all = findAll; +find.all = findAll /* Find the first tag in `tags` with a type set to `key`. */ function find(tags, key) { - var value = null; + var value = null - tags.some(function (tag) { + tags.some(function(tag) { if (tag && tag.type === key) { - value = tag; + value = tag - return true; + return true } - return false; - }); + return false + }) - return value && value.string; + return value && value.string } /* Find the first tag in `tags` with a type set to `key`. */ function findAll(tags, key) { return tags - .filter(function (tag) { - return tag && tag.type === key; + .filter(function(tag) { + return tag && tag.type === key + }) + .map(function(tag) { + return tag.string }) - .map(function (tag) { - return tag.string; - }); } diff --git a/script/util/presets.js b/script/util/presets.js index 4fb799ec..82f19bcb 100644 --- a/script/util/presets.js +++ b/script/util/presets.js @@ -1,13 +1,13 @@ -'use strict'; +'use strict' -var fs = require('fs'); +var fs = require('fs') -module.exports = rulesSync; +module.exports = rulesSync function rulesSync(filePath) { - return fs.readdirSync(filePath).filter(filter); + return fs.readdirSync(filePath).filter(filter) } function filter(basename) { - return /remark-preset-lint/.test(basename); + return /remark-preset-lint/.test(basename) } diff --git a/script/util/rule.js b/script/util/rule.js index 2f7dfc72..997f4d52 100755 --- a/script/util/rule.js +++ b/script/util/rule.js @@ -1,73 +1,78 @@ -'use strict'; +'use strict' -var fs = require('fs'); -var path = require('path'); -var dox = require('dox'); -var strip = require('strip-indent'); -var trim = require('trim'); -var find = require('./find'); +var fs = require('fs') +var path = require('path') +var dox = require('dox') +var strip = require('strip-indent') +var trim = require('trim') +var find = require('./find') -module.exports = ruleSync; +module.exports = ruleSync /* Get information for a rule at `filePath`. */ function ruleSync(filePath) { - var ruleId = path.basename(filePath); - var result = {}; - var tests = {}; - var description; - var code; - var tags; - var name; - - ruleId = ruleId.slice('remark-lint-'.length); - code = fs.readFileSync(path.join(filePath, 'index.js'), 'utf-8'); - tags = dox.parseComments(code)[0].tags; - description = find(tags, 'fileoverview'); - name = find(tags, 'module'); + var ruleId = path.basename(filePath) + var result = {} + var tests = {} + var description + var code + var tags + var name + + ruleId = ruleId.slice('remark-lint-'.length) + code = fs.readFileSync(path.join(filePath, 'index.js'), 'utf-8') + tags = dox.parseComments(code)[0].tags + description = find(tags, 'fileoverview') + name = find(tags, 'module') /* istanbul ignore if */ if (name !== ruleId) { - throw new Error( - ruleId + ' has an invalid `@module`: ' + name - ); + throw new Error(ruleId + ' has an invalid `@module`: ' + name) } /* istanbul ignore if */ if (!description) { - throw new Error(ruleId + ' is missing a `@fileoverview`'); + throw new Error(ruleId + ' is missing a `@fileoverview`') } - description = strip(description); + description = strip(description) - result.ruleId = ruleId; - result.description = trim(description); - result.tests = tests; - result.filePath = filePath; + result.ruleId = ruleId + result.description = trim(description) + result.tests = tests + result.filePath = filePath - find.all(tags, 'example').map(strip).forEach(function (example) { - var lines = example.split('\n'); - var value = strip(lines.slice(1).join('\n')); - var info; - var setting; - var context; - var name; + find + .all(tags, 'example') + .map(strip) + .forEach(check) + + return result + + function check(example) { + var lines = example.split('\n') + var value = strip(lines.slice(1).join('\n')) + var info + var setting + var context + var name try { - info = JSON.parse(lines[0]); + info = JSON.parse(lines[0]) } catch (err) { /* istanbul ignore next */ throw new Error( 'Could not parse example in ' + ruleId + ':\n' + err.stack - ); + ) } - setting = JSON.stringify(info.setting || true); - context = tests[setting]; - name = info.name; + setting = JSON.stringify(info.setting || true) + context = tests[setting] + name = info.name if (!context) { - context = []; - tests[setting] = context; + context = [] + tests[setting] = context } if (!info.label) { @@ -76,31 +81,32 @@ function ruleSync(filePath) { setting: setting, input: value, output: [] - }; + } - return; + return } /* istanbul ignore if */ if (info.label !== 'input' && info.label !== 'output') { throw new Error( 'Expected `input` or `ouput` for `label` in ' + - ruleId + ', not `' + info.label + '`' - ); + ruleId + + ', not `' + + info.label + + '`' + ) } if (!context[name]) { - context[name] = {config: info.config || {}}; + context[name] = {config: info.config || {}} } - context[name].setting = setting; + context[name].setting = setting if (info.label === 'output') { - value = value.split('\n'); + value = value.split('\n') } - context[name][info.label] = value; - }); - - return result; + context[name][info.label] = value + } } diff --git a/script/util/rules.js b/script/util/rules.js index 3d364c42..f8081a8d 100644 --- a/script/util/rules.js +++ b/script/util/rules.js @@ -1,13 +1,13 @@ -'use strict'; +'use strict' -var fs = require('fs'); +var fs = require('fs') -module.exports = rulesSync; +module.exports = rulesSync function rulesSync(filePath) { - return fs.readdirSync(filePath).filter(filter); + return fs.readdirSync(filePath).filter(filter) } function filter(basename) { - return /remark-lint/.test(basename) && basename !== 'remark-lint'; + return /remark-lint/.test(basename) && basename !== 'remark-lint' } diff --git a/test.js b/test.js index bb9961a4..f759c1b9 100644 --- a/test.js +++ b/test.js @@ -1,22 +1,22 @@ -'use strict'; +'use strict' /* eslint-disable max-params */ -var path = require('path'); -var test = require('tape'); -var vfile = require('to-vfile'); -var removePosition = require('unist-util-remove-position'); -var remark = require('remark'); -var rules = require('./script/util/rules'); -var rule = require('./script/util/rule'); -var lint = require('./packages/remark-lint'); -var noHeadingPunctuation = require('./packages/remark-lint-no-heading-punctuation'); -var noMultipleToplevelHeadings = require('./packages/remark-lint-no-multiple-toplevel-headings'); -var finalNewline = require('./packages/remark-lint-final-newline'); -var chars = require('./script/characters'); - -test('core', function (t) { - t.test('should work', function (st) { +var path = require('path') +var test = require('tape') +var vfile = require('to-vfile') +var removePosition = require('unist-util-remove-position') +var remark = require('remark') +var rules = require('./script/util/rules') +var rule = require('./script/util/rule') +var lint = require('./packages/remark-lint') +var noHeadingPunctuation = require('./packages/remark-lint-no-heading-punctuation') +var noMultipleToplevelHeadings = require('./packages/remark-lint-no-multiple-toplevel-headings') +var finalNewline = require('./packages/remark-lint-final-newline') +var chars = require('./script/characters') + +test('core', function(t) { + t.test('should work', function(st) { var doc = [ '# A heading', '', @@ -25,330 +25,340 @@ test('core', function (t) { '', '', '# Another main heading.' - ].join('\n'); + ].join('\n') - st.plan(4); + st.plan(2) remark() .use(noHeadingPunctuation) .use(noMultipleToplevelHeadings) .use(lint) - .process(vfile({path: 'virtual.md', contents: doc}), function (err, file) { - st.ifErr(err, 'should not fail'); + .process(vfile({path: 'virtual.md', contents: doc}), function(err, file) { st.deepEqual( - file.messages.map(String), + [err].concat(file.messages.map(String)), [ + null, 'virtual.md:3:1-3:24: Don’t add a trailing `.` to headings', 'virtual.md:3:1-3:24: Don’t use multiple top level headings (3:1)' ], 'should support `remark-lint` last' - ); - }); + ) + }) remark() .use(lint) .use(noHeadingPunctuation) .use(noMultipleToplevelHeadings) - .process(vfile({path: 'virtual.md', contents: doc}), function (err, file) { - st.ifErr(err, 'should not fail'); + .process(vfile({path: 'virtual.md', contents: doc}), function(err, file) { st.deepEqual( - file.messages.map(String), + [err].concat(file.messages.map(String)), [ + null, 'virtual.md:3:1-3:24: Don’t add a trailing `.` to headings', 'virtual.md:3:1-3:24: Don’t use multiple top level headings (3:1)' ], 'should support `remark-lint` first' - ); - }); - }); - - t.test('should support no rules', function (st) { - st.plan(2); - - remark().use(lint).process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.deepEqual( - file.messages.map(String), - [], - 'should warn for missing new lines' - ); - }); - }); - - t.test('should support successful rules', function (st) { - st.plan(2); + ) + }) + }) + + t.test('should support no rules', function(st) { + st.plan(1) + + remark() + .use(lint) + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null], + 'should warn for missing new lines' + ) + }) + }) + + t.test('should support successful rules', function(st) { + st.plan(1) remark() .use(finalNewline) - .process('', function (err, file) { - st.ifErr(err, 'should not fail'); - st.deepEqual(file.messages, [], 'should support successful rules'); - }); - }); + .process('', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null], + 'should support successful rules' + ) + }) + }) - t.test('should support a list with a severity', function (st) { - st.plan(3); + t.test('should support a list with a severity', function(st) { + st.plan(2) remark() .use(finalNewline, [2]) - .process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.equal( - file.messages.join(), - '1:1: Missing newline character at end of file', - 'should trigger fatally (1)' - ); - st.equal(file.messages[0].fatal, true, 'should trigger fatally (2)'); - }); - }); - - t.test('should support a boolean (`true`)', function (st) { + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null, '1:1: Missing newline character at end of file'], + 'should emit fatally (1)' + ) + st.equal(file.messages[0].fatal, true, 'should emit fatally (2)') + }) + }) + + t.test('should support a boolean (`true`)', function(st) { /* Note! This is handled by unified. */ - st.plan(2); + st.plan(1) remark() .use(finalNewline, true) - .process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.equal( - file.messages.join(), - '1:1: Missing newline character at end of file', - 'should trigger' - ); - }); - }); - - t.test('should support a boolean (`false`)', function (st) { + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null, '1:1: Missing newline character at end of file'], + 'should emit' + ) + }) + }) + + t.test('should support a boolean (`false`)', function(st) { /* Note! This is handled by unified. */ - st.plan(2); + st.plan(1) remark() .use(finalNewline, false) - .process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.deepEqual(file.messages, [], 'should not trigger'); - }); - }); + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null], + 'should not emit' + ) + }) + }) + + t.test( + 'should support a list with a boolean severity (true, for on)', + function(st) { + st.plan(1) - t.test('should support a list with a boolean severity (true, for on)', function (st) { - st.plan(2); + remark() + .use(finalNewline, [true]) + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null, '1:1: Missing newline character at end of file'], + 'should emit' + ) + }) + } + ) - remark() - .use(finalNewline, [true]) - .process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.equal( - file.messages.join(), - '1:1: Missing newline character at end of file', - 'should trigger' - ); - }); - }); - - t.test('should support a list with a boolean severity (false, for off)', function (st) { - st.plan(2); + t.test( + 'should support a list with boolean severity (false, for off)', + function(st) { + st.plan(1) - remark() - .use(finalNewline, [false]) - .process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.deepEqual(file.messages, [], 'should not trigger'); - }); - }); + remark() + .use(finalNewline, [false]) + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null], + 'should not emit' + ) + }) + } + ) - t.test('should support a list with a string severity (`error`)', function (st) { - st.plan(3); + t.test('should support a list with string severity (`error`)', function(st) { + st.plan(2) remark() .use(finalNewline, ['error']) - .process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.equal( - file.messages.join(), - '1:1: Missing newline character at end of file', - 'should trigger fatally (1)' - ); - st.equal(file.messages[0].fatal, true, 'should trigger fatally (2)'); - }); - }); - - t.test('should support a list with a string severity (`on`)', function (st) { - st.plan(3); + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null, '1:1: Missing newline character at end of file'], + 'should emit fatally (1)' + ) + st.equal(file.messages[0].fatal, true, 'should emit fatally (2)') + }) + }) + + t.test('should support a list with a string severity (`on`)', function(st) { + st.plan(2) remark() .use(finalNewline, ['on']) - .process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.equal( - file.messages.join(), - '1:1: Missing newline character at end of file', + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null, '1:1: Missing newline character at end of file'], 'should message' - ); - st.equal(file.messages[0].fatal, false, 'should *not* trigger fatally'); - }); - }); + ) + st.equal(file.messages[0].fatal, false, 'should not emit fatally') + }) + }) - t.test('should support a list with a string severity (`warn`)', function (st) { - st.plan(3); + t.test('should support a list with a string severity (`warn`)', function(st) { + st.plan(2) remark() .use(finalNewline, ['warn']) - .process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.equal( - file.messages.join(), - '1:1: Missing newline character at end of file', + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null, '1:1: Missing newline character at end of file'], 'should message' - ); - st.equal(file.messages[0].fatal, false, 'should *not* trigger fatally'); - }); - }); + ) + st.equal(file.messages[0].fatal, false, 'should not emit fatally') + }) + }) - t.test('should support a list with a string severity (`off`)', function (st) { - st.plan(2); + t.test('should support a list with a string severity (`off`)', function(st) { + st.plan(1) remark() .use(finalNewline, ['off']) - .process('.', function (err, file) { - st.ifErr(err, 'should not fail'); - st.deepEqual(file.messages, [], 'should disable `final-newline`'); - }); - }); - - t.test('should fail on invalid severities', function (st) { + .process('.', function(err, file) { + st.deepEqual( + [err].concat(file.messages.map(String)), + [null], + 'should disable `final-newline`' + ) + }) + }) + + t.test('should fail on invalid severities', function(st) { st.throws( - function () { - remark().use(finalNewline, [3]).freeze(); + function() { + remark() + .use(finalNewline, [3]) + .freeze() }, /^Error: Invalid severity `3` for `final-newline`, expected 0, 1, or 2$/, 'should throw when too high' - ); + ) st.throws( - function () { - remark().use(finalNewline, [-1]).freeze(); + function() { + remark() + .use(finalNewline, [-1]) + .freeze() }, /^Error: Invalid severity `-1` for `final-newline`, expected 0, 1, or 2$/, 'should throw too low' - ); + ) - st.end(); - }); + st.end() + }) - t.end(); -}); + t.end() +}) -test('rules', function (t) { - var root = path.join(process.cwd(), 'packages'); - var all = rules(root); +test('rules', function(t) { + var root = path.join(process.cwd(), 'packages') + var all = rules(root) - t.plan(all.length); + t.plan(all.length) - all.forEach(each); + all.forEach(each) function each(basename) { - var base = path.resolve(root, basename); - var info = rule(base); - var fn = require(base); + var base = path.resolve(root, basename) + var info = rule(base) + var fn = require(base) - t.test(info.ruleId, one); + t.test(info.ruleId, one) - function one(sst) { - assertRule(sst, fn, info); + function one(st) { + assertRule(st, fn, info) } } -}); +}) /* Assert a rule. */ function assertRule(t, rule, info) { - var tests = info.tests; - - Object.keys(tests).forEach(function (setting) { - var fixture = tests[setting]; - var config = JSON.parse(setting); - - t.test(setting, function (st) { - Object.keys(fixture).forEach(function (name) { - st.test(name, function (sst) { - assertFixture(sst, rule, info, fixture[name], name, config); - }); - }); - }); - }); - - t.end(); + var tests = info.tests + + Object.keys(tests).forEach(function(setting) { + var fixture = tests[setting] + var config = JSON.parse(setting) + + t.test(setting, function(st) { + Object.keys(fixture).forEach(function(name) { + st.test(name, function(sst) { + assertFixture(sst, rule, info, fixture[name], name, config) + }) + }) + }) + }) + + t.end() } function assertFixture(t, rule, info, fixture, basename, setting) { - var ruleId = info.ruleId; - var file = vfile(basename); - var expected = fixture.output; - var positionless = fixture.config.positionless; - var proc = remark().use(rule, setting).data('settings', fixture.config); + var ruleId = info.ruleId + var file = vfile(basename) + var expected = fixture.output + var positionless = fixture.config.positionless + var proc = remark() + .use(rule, setting) + .data('settings', fixture.config) - file.contents = preprocess(fixture.input || ''); + file.contents = preprocess(fixture.input || '') - t.plan(positionless ? 1 : 2); + t.plan(positionless ? 1 : 2) try { - proc.runSync(proc.parse(file), file); + proc.runSync(proc.parse(file), file) } catch (err) { if (err && err.source !== 'remark-lint') { - throw err; + throw err } } - t.deepEqual( - normalize(file.messages), - expected, - 'should equal with position' - ); - - file.messages.forEach(function (message) { + file.messages.forEach(function(message) { if (message.ruleId !== ruleId) { throw new Error( - 'Expected `' + ruleId + '`, not `' + - message.ruleId + '` as `ruleId` for ' + - message - ); + 'Expected `' + + ruleId + + '`, not `' + + message.ruleId + + '` as `ruleId` for ' + + message + ) } - }); + }) + + t.deepEqual(normalize(file.messages), expected, 'should equal with position') if (!positionless) { - file.messages = []; + file.messages = [] - try { - remark() - .use(function () { - return removePosition; - }) - .use(rule, setting) - .processSync(file); - } catch (err) { - console.log('err: ', err); - } + remark() + .use(clear) + .use(rule, setting) + .processSync(file) - t.deepEqual( - normalize(file.messages), - [], - 'should equal without position' - ); + t.deepEqual(normalize(file.messages), [], 'should equal without position') } - file.messages = []; + function clear() { + return removePosition + } } function normalize(messages) { - return messages.map(function (message) { - var value = String(message); - return value.slice(value.indexOf(':') + 1); - }); + return messages.map(function(message) { + var value = String(message) + return value.slice(value.indexOf(':') + 1) + }) } function preprocess(value) { - chars.forEach(function (char) { - value = value.replace(char.in, char.out); - }); + chars.forEach(function(char) { + value = value.replace(char.in, char.out) + }) - return value; + return value }