.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-trailing-spaces.js
1 /**
2  * @fileoverview Disallow trailing spaces at the end of lines.
3  * @author Nodeca Team <https://github.com/nodeca>
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const astUtils = require("./utils/ast-utils");
12
13 //------------------------------------------------------------------------------
14 // Rule Definition
15 //------------------------------------------------------------------------------
16
17 module.exports = {
18     meta: {
19         type: "layout",
20
21         docs: {
22             description: "disallow trailing whitespace at the end of lines",
23             category: "Stylistic Issues",
24             recommended: false,
25             url: "https://eslint.org/docs/rules/no-trailing-spaces"
26         },
27
28         fixable: "whitespace",
29
30         schema: [
31             {
32                 type: "object",
33                 properties: {
34                     skipBlankLines: {
35                         type: "boolean",
36                         default: false
37                     },
38                     ignoreComments: {
39                         type: "boolean",
40                         default: false
41                     }
42                 },
43                 additionalProperties: false
44             }
45         ],
46
47         messages: {
48             trailingSpace: "Trailing spaces not allowed."
49         }
50     },
51
52     create(context) {
53         const sourceCode = context.getSourceCode();
54
55         const BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u3000]",
56             SKIP_BLANK = `^${BLANK_CLASS}*$`,
57             NONBLANK = `${BLANK_CLASS}+$`;
58
59         const options = context.options[0] || {},
60             skipBlankLines = options.skipBlankLines || false,
61             ignoreComments = options.ignoreComments || false;
62
63         /**
64          * Report the error message
65          * @param {ASTNode} node node to report
66          * @param {int[]} location range information
67          * @param {int[]} fixRange Range based on the whole program
68          * @returns {void}
69          */
70         function report(node, location, fixRange) {
71
72             /*
73              * Passing node is a bit dirty, because message data will contain big
74              * text in `source`. But... who cares :) ?
75              * One more kludge will not make worse the bloody wizardry of this
76              * plugin.
77              */
78             context.report({
79                 node,
80                 loc: location,
81                 messageId: "trailingSpace",
82                 fix(fixer) {
83                     return fixer.removeRange(fixRange);
84                 }
85             });
86         }
87
88         /**
89          * Given a list of comment nodes, return the line numbers for those comments.
90          * @param {Array} comments An array of comment nodes.
91          * @returns {number[]} An array of line numbers containing comments.
92          */
93         function getCommentLineNumbers(comments) {
94             const lines = new Set();
95
96             comments.forEach(comment => {
97                 const endLine = comment.type === "Block"
98                     ? comment.loc.end.line - 1
99                     : comment.loc.end.line;
100
101                 for (let i = comment.loc.start.line; i <= endLine; i++) {
102                     lines.add(i);
103                 }
104             });
105
106             return lines;
107         }
108
109         //--------------------------------------------------------------------------
110         // Public
111         //--------------------------------------------------------------------------
112
113         return {
114
115             Program: function checkTrailingSpaces(node) {
116
117                 /*
118                  * Let's hack. Since Espree does not return whitespace nodes,
119                  * fetch the source code and do matching via regexps.
120                  */
121
122                 const re = new RegExp(NONBLANK, "u"),
123                     skipMatch = new RegExp(SKIP_BLANK, "u"),
124                     lines = sourceCode.lines,
125                     linebreaks = sourceCode.getText().match(astUtils.createGlobalLinebreakMatcher()),
126                     comments = sourceCode.getAllComments(),
127                     commentLineNumbers = getCommentLineNumbers(comments);
128
129                 let totalLength = 0,
130                     fixRange = [];
131
132                 for (let i = 0, ii = lines.length; i < ii; i++) {
133                     const lineNumber = i + 1;
134
135                     /*
136                      * Always add linebreak length to line length to accommodate for line break (\n or \r\n)
137                      * Because during the fix time they also reserve one spot in the array.
138                      * Usually linebreak length is 2 for \r\n (CRLF) and 1 for \n (LF)
139                      */
140                     const linebreakLength = linebreaks && linebreaks[i] ? linebreaks[i].length : 1;
141                     const lineLength = lines[i].length + linebreakLength;
142
143                     const matches = re.exec(lines[i]);
144
145                     if (matches) {
146                         const location = {
147                             start: {
148                                 line: lineNumber,
149                                 column: matches.index
150                             },
151                             end: {
152                                 line: lineNumber,
153                                 column: lineLength - linebreakLength
154                             }
155                         };
156
157                         const rangeStart = totalLength + location.start.column;
158                         const rangeEnd = totalLength + location.end.column;
159                         const containingNode = sourceCode.getNodeByRangeIndex(rangeStart);
160
161                         if (containingNode && containingNode.type === "TemplateElement" &&
162                           rangeStart > containingNode.parent.range[0] &&
163                           rangeEnd < containingNode.parent.range[1]) {
164                             totalLength += lineLength;
165                             continue;
166                         }
167
168                         /*
169                          * If the line has only whitespace, and skipBlankLines
170                          * is true, don't report it
171                          */
172                         if (skipBlankLines && skipMatch.test(lines[i])) {
173                             totalLength += lineLength;
174                             continue;
175                         }
176
177                         fixRange = [rangeStart, rangeEnd];
178
179                         if (!ignoreComments || !commentLineNumbers.has(lineNumber)) {
180                             report(node, location, fixRange);
181                         }
182                     }
183
184                     totalLength += lineLength;
185                 }
186             }
187
188         };
189     }
190 };