2 * @fileoverview Disallow use of multiple spaces.
3 * @author Nicholas C. Zakas
8 const astUtils = require("./utils/ast-utils");
10 //------------------------------------------------------------------------------
12 //------------------------------------------------------------------------------
19 description: "disallow multiple spaces",
20 category: "Best Practices",
22 url: "https://eslint.org/docs/rules/no-multi-spaces"
25 fixable: "whitespace",
38 additionalProperties: false
45 additionalProperties: false
51 const sourceCode = context.getSourceCode();
52 const options = context.options[0] || {};
53 const ignoreEOLComments = options.ignoreEOLComments;
54 const exceptions = Object.assign({ Property: true }, options.exceptions);
55 const hasExceptions = Object.keys(exceptions).filter(key => exceptions[key]).length > 0;
58 * Formats value of given comment token for error message by truncating its length.
59 * @param {Token} token comment token
60 * @returns {string} formatted value
63 function formatReportedCommentValue(token) {
64 const valueLines = token.value.split("\n");
65 const value = valueLines[0];
66 const formattedValue = `${value.slice(0, 12)}...`;
68 return valueLines.length === 1 && value.length <= 12 ? value : formattedValue;
71 //--------------------------------------------------------------------------
73 //--------------------------------------------------------------------------
77 sourceCode.tokensAndComments.forEach((leftToken, leftIndex, tokensAndComments) => {
78 if (leftIndex === tokensAndComments.length - 1) {
81 const rightToken = tokensAndComments[leftIndex + 1];
83 // Ignore tokens that don't have 2 spaces between them or are on different lines
85 !sourceCode.text.slice(leftToken.range[1], rightToken.range[0]).includes(" ") ||
86 leftToken.loc.end.line < rightToken.loc.start.line
91 // Ignore comments that are the last token on their line if `ignoreEOLComments` is active.
94 astUtils.isCommentToken(rightToken) &&
96 leftIndex === tokensAndComments.length - 2 ||
97 rightToken.loc.end.line < tokensAndComments[leftIndex + 2].loc.start.line
103 // Ignore tokens that are in a node in the "exceptions" object
105 const parentNode = sourceCode.getNodeByRangeIndex(rightToken.range[0] - 1);
107 if (parentNode && exceptions[parentNode.type]) {
114 if (rightToken.type === "Block") {
115 displayValue = `/*${formatReportedCommentValue(rightToken)}*/`;
116 } else if (rightToken.type === "Line") {
117 displayValue = `//${formatReportedCommentValue(rightToken)}`;
119 displayValue = rightToken.value;
124 loc: { start: leftToken.loc.end, end: rightToken.loc.start },
125 message: "Multiple spaces found before '{{displayValue}}'.",
126 data: { displayValue },
127 fix: fixer => fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " ")