UNPKG

3.59 kBJavaScriptView Raw
1/**
2 * @fileoverview Disallow trailing spaces at the end of lines.
3 * @author Nodeca Team <https://github.com/nodeca>
4 * @copyright 2015 Greg Cochard
5 */
6"use strict";
7
8//------------------------------------------------------------------------------
9// Rule Definition
10//------------------------------------------------------------------------------
11
12module.exports = function(context) {
13
14 var BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u2028\u2029\u3000]",
15 SKIP_BLANK = "^" + BLANK_CLASS + "*$",
16 NONBLANK = BLANK_CLASS + "+$";
17
18 var options = context.options[0] || {},
19 skipBlankLines = options.skipBlankLines || false;
20
21 /**
22 * Report the error message
23 * @param {ASTNode} node node to report
24 * @param {int[]} location range information
25 * @param {int[]} fixRange Range based on the whole program
26 * @returns {void}
27 */
28 function report(node, location, fixRange) {
29 // Passing node is a bit dirty, because message data will contain
30 // big text in `source`. But... who cares :) ?
31 // One more kludge will not make worse the bloody wizardry of this plugin.
32 context.report({
33 node: node,
34 loc: location,
35 message: "Trailing spaces not allowed.",
36 fix: function(fixer) {
37 return fixer.removeRange(fixRange);
38 }
39 });
40 }
41
42
43 //--------------------------------------------------------------------------
44 // Public
45 //--------------------------------------------------------------------------
46
47 return {
48
49 "Program": function checkTrailingSpaces(node) {
50
51 // Let's hack. Since Espree does not return whitespace nodes,
52 // fetch the source code and do matching via regexps.
53
54 var src = context.getSource(),
55 re = new RegExp(NONBLANK),
56 skipMatch = new RegExp(SKIP_BLANK),
57 matches, lines = src.split(/\r?\n/),
58 linebreaks = context.getSource().match(/\r\n|\r|\n|\u2028|\u2029/g),
59 location,
60 totalLength = 0,
61 fixRange = [];
62
63 for (var i = 0, ii = lines.length; i < ii; i++) {
64 matches = re.exec(lines[i]);
65
66 // Always add linebreak length to line length to accommodate for line break (\n or \r\n)
67 // Because during the fix time they also reserve one spot in the array.
68 // Usually linebreak length is 2 for \r\n (CRLF) and 1 for \n (LF)
69 var linebreakLength = linebreaks && linebreaks[i] ? linebreaks[i].length : 1;
70 var lineLength = lines[i].length + linebreakLength;
71
72 if (matches) {
73
74 // If the line has only whitespace, and skipBlankLines
75 // is true, don't report it
76 if (skipBlankLines && skipMatch.test(lines[i])) {
77 continue;
78 }
79 location = {
80 line: i + 1,
81 column: matches.index
82 };
83
84 fixRange = [totalLength + location.column, totalLength + lineLength - linebreakLength];
85
86 report(node, location, fixRange);
87 }
88
89 totalLength += lineLength;
90 }
91 }
92
93 };
94};
95
96module.exports.schema = [
97 {
98 "type": "object",
99 "properties": {
100 "skipBlankLines": {
101 "type": "boolean"
102 }
103 },
104 "additionalProperties": false
105 }
106];