Blame view
node_modules/eslint/lib/rules/no-multi-spaces.js
5.03 KB
f7563de62
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
/** * @fileoverview Disallow use of multiple spaces. * @author Nicholas C. Zakas */ "use strict"; const astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: "disallow multiple spaces", category: "Best Practices", recommended: false }, fixable: "whitespace", schema: [ { type: "object", properties: { exceptions: { type: "object", patternProperties: { "^([A-Z][a-z]*)+$": { type: "boolean" } }, additionalProperties: false } }, additionalProperties: false } ] }, create(context) { // the index of the last comment that was checked const exceptions = { Property: true }, options = context.options[0]; let hasExceptions = true, lastCommentIndex = 0; if (options && options.exceptions) { Object.keys(options.exceptions).forEach(key => { if (options.exceptions[key]) { exceptions[key] = true; } else { delete exceptions[key]; } }); hasExceptions = Object.keys(exceptions).length > 0; } /** * Determines if a given source index is in a comment or not by checking * the index against the comment range. Since the check goes straight * through the file, once an index is passed a certain comment, we can * go to the next comment to check that. * @param {int} index The source index to check. * @param {ASTNode[]} comments An array of comment nodes. * @returns {boolean} True if the index is within a comment, false if not. * @private */ function isIndexInComment(index, comments) { while (lastCommentIndex < comments.length) { const comment = comments[lastCommentIndex]; if (comment.range[0] <= index && index < comment.range[1]) { return true; } else if (index > comment.range[1]) { lastCommentIndex++; } else { break; } } return false; } //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { Program() { const sourceCode = context.getSourceCode(), source = sourceCode.getText(), allComments = sourceCode.getAllComments(), JOINED_LINEBEAKS = Array.from(astUtils.LINEBREAKS).join(""), pattern = new RegExp(String.raw`[^ \t${JOINED_LINEBEAKS}].? {2,}`, "g"); // note: repeating space let parent; /** * Creates a fix function that removes the multiple spaces between the two tokens * @param {RuleFixer} leftToken left token * @param {RuleFixer} rightToken right token * @returns {Function} fix function * @private */ function createFix(leftToken, rightToken) { return function(fixer) { return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " "); }; } while (pattern.test(source)) { // do not flag anything inside of comments if (!isIndexInComment(pattern.lastIndex, allComments)) { const token = sourceCode.getTokenByRangeStart(pattern.lastIndex); if (token) { const previousToken = sourceCode.getTokenBefore(token); if (hasExceptions) { parent = sourceCode.getNodeByRangeIndex(pattern.lastIndex - 1); } if (!parent || !exceptions[parent.type]) { context.report({ node: token, loc: token.loc.start, message: "Multiple spaces found before '{{value}}'.", data: { value: token.value }, fix: createFix(previousToken, token) }); } } } } } }; } }; |