2 * @fileoverview Require spaces around infix operators
3 * @author Michael Ficarra
7 //------------------------------------------------------------------------------
9 //------------------------------------------------------------------------------
16 description: "require spacing around infix operators",
17 category: "Stylistic Issues",
19 url: "https://eslint.org/docs/rules/space-infix-ops"
22 fixable: "whitespace",
33 additionalProperties: false
39 const int32Hint = context.options[0] ? context.options[0].int32Hint === true : false;
40 const sourceCode = context.getSourceCode();
43 * Returns the first token which violates the rule
44 * @param {ASTNode} left The left node of the main node
45 * @param {ASTNode} right The right node of the main node
46 * @param {string} op The operator of the main node
47 * @returns {Object} The violator token or null
50 function getFirstNonSpacedToken(left, right, op) {
51 const operator = sourceCode.getFirstTokenBetween(left, right, token => token.value === op);
52 const prev = sourceCode.getTokenBefore(operator);
53 const next = sourceCode.getTokenAfter(operator);
55 if (!sourceCode.isSpaceBetweenTokens(prev, operator) || !sourceCode.isSpaceBetweenTokens(operator, next)) {
63 * Reports an AST node as a rule violation
64 * @param {ASTNode} mainNode The node to report
65 * @param {Object} culpritToken The token which has a problem
69 function report(mainNode, culpritToken) {
72 loc: culpritToken.loc,
73 message: "Operator '{{operator}}' must be spaced.",
75 operator: culpritToken.value
78 const previousToken = sourceCode.getTokenBefore(culpritToken);
79 const afterToken = sourceCode.getTokenAfter(culpritToken);
82 if (culpritToken.range[0] - previousToken.range[1] === 0) {
86 fixString += culpritToken.value;
88 if (afterToken.range[0] - culpritToken.range[1] === 0) {
92 return fixer.replaceText(culpritToken, fixString);
98 * Check if the node is binary then report
99 * @param {ASTNode} node node to evaluate
103 function checkBinary(node) {
104 const leftNode = (node.left.typeAnnotation) ? node.left.typeAnnotation : node.left;
105 const rightNode = node.right;
107 // search for = in AssignmentPattern nodes
108 const operator = node.operator || "=";
110 const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode, operator);
113 if (!(int32Hint && sourceCode.getText(node).endsWith("|0"))) {
114 report(node, nonSpacedNode);
120 * Check if the node is conditional
121 * @param {ASTNode} node node to evaluate
125 function checkConditional(node) {
126 const nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent, "?");
127 const nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate, ":");
129 if (nonSpacedConsequesntNode) {
130 report(node, nonSpacedConsequesntNode);
131 } else if (nonSpacedAlternateNode) {
132 report(node, nonSpacedAlternateNode);
137 * Check if the node is a variable
138 * @param {ASTNode} node node to evaluate
142 function checkVar(node) {
143 const leftNode = (node.id.typeAnnotation) ? node.id.typeAnnotation : node.id;
144 const rightNode = node.init;
147 const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode, "=");
150 report(node, nonSpacedNode);
156 AssignmentExpression: checkBinary,
157 AssignmentPattern: checkBinary,
158 BinaryExpression: checkBinary,
159 LogicalExpression: checkBinary,
160 ConditionalExpression: checkConditional,
161 VariableDeclarator: checkVar