1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | module.exports = function(context) {
|
12 | var int32Hint = context.options[0] ? context.options[0].int32Hint === true : false;
|
13 |
|
14 | var OPERATORS = [
|
15 | "*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", "in",
|
16 | "instanceof", "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", "=",
|
17 | "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|=",
|
18 | "?", ":", ","
|
19 | ];
|
20 |
|
21 | |
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | function getFirstNonSpacedToken(left, right) {
|
29 | var op, tokens = context.getTokensBetween(left, right, 1);
|
30 | for (var i = 1, l = tokens.length - 1; i < l; ++i) {
|
31 | op = tokens[i];
|
32 | if (
|
33 | op.type === "Punctuator" &&
|
34 | OPERATORS.indexOf(op.value) >= 0 &&
|
35 | (tokens[i - 1].range[1] >= op.range[0] || op.range[1] >= tokens[i + 1].range[0])
|
36 | ) {
|
37 | return op;
|
38 | }
|
39 | }
|
40 | return null;
|
41 | }
|
42 |
|
43 | |
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | function report(mainNode, culpritToken) {
|
51 | context.report({
|
52 | node: mainNode,
|
53 | loc: culpritToken.loc.start,
|
54 | message: "Infix operators must be spaced.",
|
55 | fix: function(fixer) {
|
56 | var previousToken = context.getTokenBefore(culpritToken);
|
57 | var afterToken = context.getTokenAfter(culpritToken);
|
58 | var fixString = "";
|
59 |
|
60 | if (culpritToken.range[0] - previousToken.range[1] === 0) {
|
61 | fixString = " ";
|
62 | }
|
63 |
|
64 | fixString += culpritToken.value;
|
65 |
|
66 | if (afterToken.range[0] - culpritToken.range[1] === 0) {
|
67 | fixString += " ";
|
68 | }
|
69 |
|
70 | return fixer.replaceText(culpritToken, fixString);
|
71 | }
|
72 | });
|
73 | }
|
74 |
|
75 | |
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | function checkBinary(node) {
|
82 | var nonSpacedNode = getFirstNonSpacedToken(node.left, node.right);
|
83 |
|
84 | if (nonSpacedNode) {
|
85 | if (!(int32Hint && context.getSource(node).substr(-2) === "|0")) {
|
86 | report(node, nonSpacedNode);
|
87 | }
|
88 | }
|
89 | }
|
90 |
|
91 | |
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | function checkConditional(node) {
|
98 | var nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent);
|
99 | var nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate);
|
100 |
|
101 | if (nonSpacedConsequesntNode) {
|
102 | report(node, nonSpacedConsequesntNode);
|
103 | } else if (nonSpacedAlternateNode) {
|
104 | report(node, nonSpacedAlternateNode);
|
105 | }
|
106 | }
|
107 |
|
108 | |
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 | function checkVar(node) {
|
115 | var nonSpacedNode;
|
116 |
|
117 | if (node.init) {
|
118 | nonSpacedNode = getFirstNonSpacedToken(node.id, node.init);
|
119 | if (nonSpacedNode) {
|
120 | report(node, nonSpacedNode);
|
121 | }
|
122 | }
|
123 | }
|
124 |
|
125 | return {
|
126 | "AssignmentExpression": checkBinary,
|
127 | "AssignmentPattern": checkBinary,
|
128 | "BinaryExpression": checkBinary,
|
129 | "LogicalExpression": checkBinary,
|
130 | "ConditionalExpression": checkConditional,
|
131 | "VariableDeclarator": checkVar
|
132 | };
|
133 |
|
134 | };
|
135 |
|
136 | module.exports.schema = [
|
137 | {
|
138 | "type": "object",
|
139 | "properties": {
|
140 | "int32Hint": {
|
141 | "type": "boolean"
|
142 | }
|
143 | },
|
144 | "additionalProperties": false
|
145 | }
|
146 | ];
|