UNPKG

5.48 kBJavaScriptView Raw
1/**
2 * @fileoverview Require spaces around infix operators
3 * @author Michael Ficarra
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Rule Definition
9//------------------------------------------------------------------------------
10
11module.exports = {
12 meta: {
13 type: "layout",
14
15 docs: {
16 description: "require spacing around infix operators",
17 category: "Stylistic Issues",
18 recommended: false,
19 url: "https://eslint.org/docs/rules/space-infix-ops"
20 },
21
22 fixable: "whitespace",
23
24 schema: [
25 {
26 type: "object",
27 properties: {
28 int32Hint: {
29 type: "boolean",
30 default: false
31 }
32 },
33 additionalProperties: false
34 }
35 ]
36 },
37
38 create(context) {
39 const int32Hint = context.options[0] ? context.options[0].int32Hint === true : false;
40 const sourceCode = context.getSourceCode();
41
42 /**
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
48 * @private
49 */
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);
54
55 if (!sourceCode.isSpaceBetweenTokens(prev, operator) || !sourceCode.isSpaceBetweenTokens(operator, next)) {
56 return operator;
57 }
58
59 return null;
60 }
61
62 /**
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
66 * @returns {void}
67 * @private
68 */
69 function report(mainNode, culpritToken) {
70 context.report({
71 node: mainNode,
72 loc: culpritToken.loc.start,
73 message: "Operator '{{operator}}' must be spaced.",
74 data: {
75 operator: culpritToken.value
76 },
77 fix(fixer) {
78 const previousToken = sourceCode.getTokenBefore(culpritToken);
79 const afterToken = sourceCode.getTokenAfter(culpritToken);
80 let fixString = "";
81
82 if (culpritToken.range[0] - previousToken.range[1] === 0) {
83 fixString = " ";
84 }
85
86 fixString += culpritToken.value;
87
88 if (afterToken.range[0] - culpritToken.range[1] === 0) {
89 fixString += " ";
90 }
91
92 return fixer.replaceText(culpritToken, fixString);
93 }
94 });
95 }
96
97 /**
98 * Check if the node is binary then report
99 * @param {ASTNode} node node to evaluate
100 * @returns {void}
101 * @private
102 */
103 function checkBinary(node) {
104 const leftNode = (node.left.typeAnnotation) ? node.left.typeAnnotation : node.left;
105 const rightNode = node.right;
106
107 // search for = in AssignmentPattern nodes
108 const operator = node.operator || "=";
109
110 const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode, operator);
111
112 if (nonSpacedNode) {
113 if (!(int32Hint && sourceCode.getText(node).endsWith("|0"))) {
114 report(node, nonSpacedNode);
115 }
116 }
117 }
118
119 /**
120 * Check if the node is conditional
121 * @param {ASTNode} node node to evaluate
122 * @returns {void}
123 * @private
124 */
125 function checkConditional(node) {
126 const nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent, "?");
127 const nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate, ":");
128
129 if (nonSpacedConsequesntNode) {
130 report(node, nonSpacedConsequesntNode);
131 } else if (nonSpacedAlternateNode) {
132 report(node, nonSpacedAlternateNode);
133 }
134 }
135
136 /**
137 * Check if the node is a variable
138 * @param {ASTNode} node node to evaluate
139 * @returns {void}
140 * @private
141 */
142 function checkVar(node) {
143 const leftNode = (node.id.typeAnnotation) ? node.id.typeAnnotation : node.id;
144 const rightNode = node.init;
145
146 if (rightNode) {
147 const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode, "=");
148
149 if (nonSpacedNode) {
150 report(node, nonSpacedNode);
151 }
152 }
153 }
154
155 return {
156 AssignmentExpression: checkBinary,
157 AssignmentPattern: checkBinary,
158 BinaryExpression: checkBinary,
159 LogicalExpression: checkBinary,
160 ConditionalExpression: checkConditional,
161 VariableDeclarator: checkVar
162 };
163
164 }
165};