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