-
-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New rule which warns when the checkbox character is invalid or inconsistent. Closes GH-4.
- Loading branch information
Showing
11 changed files
with
581 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
/** | ||
* @author Titus Wormer | ||
* @copyright 2015 Titus Wormer. All rights reserved. | ||
* @module checkbox-character-style | ||
* @fileoverview | ||
* Warn when list item checkboxes violate a given style. | ||
* | ||
* The default value, `consistent`, detects the first used checked | ||
* and unchecked checkbox styles, and will warn when a subsequent | ||
* checkboxes uses a different style. | ||
* | ||
* These values can also be passed in as an object, such as: | ||
* | ||
* ```json | ||
* { | ||
* "checked": 'x', | ||
* "unchecked": ' ' | ||
* } | ||
* ``` | ||
* @example | ||
* <!-- Note: the double guillemet (`»`) and middle-dots represent a tab --> | ||
* | ||
* <!-- Valid by default, `'consistent'`, or `{'checked': 'x'}` --> | ||
* - [x] List item | ||
* - [x] List item | ||
* | ||
* <!-- Valid by default, `'consistent'`, or `{'checked': 'X'}` --> | ||
* - [X] List item | ||
* - [X] List item | ||
* | ||
* <!-- Valid by default, `'consistent'`, or `{'unchecked': ' '}` --> | ||
* - [ ] List item | ||
* - [ ] List item | ||
* | ||
* <!-- Valid by default, `'consistent'`, or `{'unchecked': '»'}` --> | ||
* - [»···] List item | ||
* - [»···] List item | ||
* | ||
* <!-- Always invalid --> | ||
* - [x] List item | ||
* - [X] List item | ||
* - [ ] List item | ||
* - [»···] List item | ||
*/ | ||
|
||
'use strict'; | ||
|
||
/* | ||
* Dependencies. | ||
*/ | ||
|
||
var visit = require('../utilities/visit'); | ||
var position = require('../utilities/position'); | ||
|
||
/* | ||
* Methods. | ||
*/ | ||
|
||
var start = position.start; | ||
var end = position.end; | ||
|
||
var CHECKED = { | ||
'x': true, | ||
'X': true | ||
}; | ||
|
||
var UNCHECKED = { | ||
' ': true, | ||
' ': true | ||
}; | ||
|
||
/** | ||
* Warn when list item checkboxes violate a given style. | ||
* | ||
* @param {Node} ast - Root node. | ||
* @param {File} file - Virtual file. | ||
* @param {Object?} preferred - An object with `checked` | ||
* and `unchecked` properties, each set to null to default to | ||
* the first found style, or set to `'x'` or `'X'` for checked, | ||
* or `' '` (space) or `'\t'` (tab) for unchecked. | ||
* @param {Function} done - Callback. | ||
*/ | ||
function checkboxCharacterStyle(ast, file, preferred, done) { | ||
var contents = file.toString(); | ||
|
||
if (preferred === 'consistent' || typeof preferred !== 'object') { | ||
preferred = {}; | ||
} | ||
|
||
if (!preferred.unchecked) { | ||
preferred.unchecked = null; | ||
} | ||
|
||
if (!preferred.checked) { | ||
preferred.checked = null; | ||
} | ||
|
||
if ( | ||
preferred.unchecked !== null && | ||
UNCHECKED[preferred.unchecked] !== true | ||
) { | ||
file.fail( | ||
'Invalid unchecked checkbox marker `' + | ||
preferred.unchecked + | ||
'`: use either `\'\\t\'`, or `\' \'`' | ||
); | ||
} | ||
|
||
if ( | ||
preferred.checked !== null && | ||
CHECKED[preferred.checked] !== true | ||
) { | ||
file.fail( | ||
'Invalid checked checkbox marker `' + | ||
preferred.checked + | ||
'`: use either `\'x\'`, or `\'X\'`' | ||
); | ||
} | ||
|
||
visit(ast, 'listItem', function (node) { | ||
var type; | ||
var initial; | ||
var final; | ||
var stop; | ||
var value; | ||
var style; | ||
var character; | ||
|
||
/* | ||
* Exit early for items without checkbox. | ||
*/ | ||
|
||
if ( | ||
node.checked !== Boolean(node.checked) || | ||
position.isGenerated(node) | ||
) { | ||
return; | ||
} | ||
|
||
type = node.checked ? 'checked' : 'unchecked'; | ||
|
||
initial = start(node).offset; | ||
final = (node.children.length ? start(node.children[0]) : end(node)).offset; | ||
|
||
/* | ||
* For a checkbox to be parsed, it must be followed | ||
* by a white space. | ||
*/ | ||
|
||
value = contents.slice(initial, final).trimRight().slice(0, -1); | ||
|
||
/* | ||
* The checkbox character is behind a square | ||
* bracket. | ||
*/ | ||
|
||
character = value.charAt(value.length - 1); | ||
style = preferred[type]; | ||
|
||
if (style === null) { | ||
preferred[type] = character; | ||
} else if (character !== style) { | ||
stop = initial + value.length; | ||
|
||
file.warn( | ||
type.charAt(0).toUpperCase() + type.slice(1) + | ||
' checkboxes should use `' + style + '` as a marker', | ||
{ | ||
'start': file.offsetToPosition(stop - 1), | ||
'end': file.offsetToPosition(stop) | ||
} | ||
); | ||
} | ||
}); | ||
|
||
done(); | ||
} | ||
|
||
/* | ||
* Expose. | ||
*/ | ||
|
||
module.exports = checkboxCharacterStyle; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.