Skip to content

Commit 179b7df

Browse files
authored
Fix cases without space after keywords (#1436)
1 parent 2ba83ad commit 179b7df

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1101
-66
lines changed

rules/explicit-length-check.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const isLiteralValue = require('./utils/is-literal-value.js');
55
const isLogicalExpression = require('./utils/is-logical-expression.js');
66
const {isBooleanNode, getBooleanAncestor} = require('./utils/boolean.js');
77
const {memberExpressionSelector} = require('./selectors/index.js');
8+
const {fixSpaceAroundKeyword} = require('./fix/index.js');
89

910
const TYPE_NON_ZERO = 'non-zero';
1011
const TYPE_ZERO = 'zero';
@@ -110,12 +111,15 @@ function create(context) {
110111
if (
111112
!isParenthesized(node, sourceCode) &&
112113
node.type === 'UnaryExpression' &&
113-
node.parent.type === 'UnaryExpression'
114+
(node.parent.type === 'UnaryExpression' || node.parent.type === 'AwaitExpression')
114115
) {
115116
fixed = `(${fixed})`;
116117
}
117118

118-
const fix = fixer => fixer.replaceText(node, fixed);
119+
const fix = function * (fixer) {
120+
yield fixer.replaceText(node, fixed);
121+
yield * fixSpaceAroundKeyword(fixer, node, sourceCode);
122+
};
119123

120124
const problem = {
121125
node,
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
'use strict';
2+
3+
const isKeywordToken = keyword => ({type, value}) => type === 'Keyword' && value === keyword;
4+
5+
function * fixSpaceAroundKeyword(fixer, node, sourceCode) {
6+
const {parent} = node;
7+
const keywords = [];
8+
9+
switch (parent.type) {
10+
case 'YieldExpression':
11+
if (parent.delegate) {
12+
break;
13+
}
14+
// Fallthrough
15+
16+
case 'ReturnStatement':
17+
case 'ThrowStatement':
18+
case 'AwaitExpression': {
19+
/* istanbul ignore else */
20+
if (parent.argument === node) {
21+
keywords.push({
22+
keyword: sourceCode.getFirstToken(parent),
23+
side: 'after',
24+
});
25+
}
26+
27+
break;
28+
}
29+
30+
case 'UnaryExpression': {
31+
const {operator, prefix, argument: unaryExpressionArgument} = parent;
32+
/* istanbul ignore else */
33+
if (
34+
(
35+
operator === 'typeof' ||
36+
operator === 'void' ||
37+
operator === 'delete'
38+
) &&
39+
prefix &&
40+
unaryExpressionArgument === node
41+
) {
42+
keywords.push({
43+
keyword: sourceCode.getFirstToken(parent),
44+
side: 'after',
45+
});
46+
}
47+
48+
break;
49+
}
50+
51+
case 'BinaryExpression': {
52+
const {operator, left} = parent;
53+
/* istanbul ignore else */
54+
if (
55+
operator === 'in' ||
56+
operator === 'instanceof'
57+
) {
58+
keywords.push({
59+
keyword: sourceCode.getTokenAfter(left, {filter: isKeywordToken(operator)}),
60+
side: left === node ? 'before' : 'after',
61+
});
62+
}
63+
64+
break;
65+
}
66+
67+
case 'ExportDefaultDeclaration': {
68+
/* istanbul ignore else */
69+
if (parent.declaration === node) {
70+
keywords.push({
71+
keyword: sourceCode.getFirstToken(parent, {filter: isKeywordToken('default')}),
72+
side: 'after',
73+
});
74+
}
75+
76+
break;
77+
}
78+
79+
case 'ExpressionStatement': {
80+
/* istanbul ignore else */
81+
if (parent.expression === node) {
82+
yield * fixSpaceAroundKeyword(fixer, parent, sourceCode);
83+
return;
84+
}
85+
86+
/* istanbul ignore next */
87+
break;
88+
}
89+
90+
case 'IfStatement': {
91+
/* istanbul ignore else */
92+
if (parent.alternate === node) {
93+
keywords.push({
94+
keyword: sourceCode.getTokenBefore(node, {filter: isKeywordToken('else')}),
95+
side: 'after',
96+
});
97+
}
98+
99+
break;
100+
}
101+
102+
case 'DoWhileStatement': {
103+
/* istanbul ignore else */
104+
if (parent.body === node) {
105+
keywords.push({
106+
keyword: sourceCode.getFirstToken(parent),
107+
side: 'after',
108+
});
109+
}
110+
111+
break;
112+
}
113+
114+
case 'SwitchCase': {
115+
/* istanbul ignore else */
116+
if (parent.test === node) {
117+
keywords.push({
118+
keyword: sourceCode.getTokenBefore(node, {filter: isKeywordToken('case')}),
119+
side: 'after',
120+
});
121+
}
122+
123+
break;
124+
}
125+
126+
case 'VariableDeclarator': {
127+
const grandParent = parent.parent;
128+
if (
129+
grandParent.type === 'VariableDeclaration' &&
130+
grandParent.declarations[0] === parent
131+
) {
132+
keywords.push({
133+
keyword: sourceCode.getFirstToken(grandParent),
134+
side: 'after',
135+
});
136+
}
137+
138+
break;
139+
}
140+
141+
case 'ForOfStatement': {
142+
// Note: Other keywords and children not handled, because not using
143+
if (parent.right === node) {
144+
keywords.push({
145+
keyword: sourceCode.getTokenBefore(node, {filter: ({type, value}) => type === 'Identifier' && value === 'of'}),
146+
side: 'after',
147+
});
148+
}
149+
150+
break;
151+
}
152+
153+
case 'ForInStatement': {
154+
// Note: Other keywords and children not handled, because not using
155+
if (parent.right === node) {
156+
keywords.push({
157+
keyword: sourceCode.getTokenBefore(node, {filter: isKeywordToken('in')}),
158+
side: 'after',
159+
});
160+
}
161+
162+
break;
163+
}
164+
165+
case 'ClassDeclaration':
166+
case 'ClassExpression': {
167+
/* istanbul ignore else */
168+
if (parent.superClass === node) {
169+
keywords.push({
170+
keyword: sourceCode.getTokenBefore(node, {filter: isKeywordToken('extends')}),
171+
side: 'after',
172+
});
173+
}
174+
175+
break;
176+
}
177+
178+
// No default
179+
}
180+
181+
for (const {keyword, side} of keywords) {
182+
const characterIndex = side === 'before' ?
183+
keyword.range[0] - 1 :
184+
keyword.range[1];
185+
186+
if (sourceCode.text.charAt(characterIndex) !== ' ') {
187+
yield fixer[side === 'before' ? 'insertTextBefore' : 'insertTextAfter'](keyword, ' ');
188+
}
189+
}
190+
}
191+
192+
module.exports = fixSpaceAroundKeyword;

rules/fix/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ module.exports = {
1515
renameVariable: require('./rename-variable.js'),
1616
replaceNodeOrTokenAndSpacesBefore: require('./replace-node-or-token-and-spaces-before.js'),
1717
removeSpacesAfter: require('./remove-spaces-after.js'),
18+
fixSpaceAroundKeyword: require('./fix-space-around-keywords.js'),
1819
};

rules/no-array-for-each.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const {getParentheses} = require('./utils/parentheses.js');
1515
const isFunctionSelfUsedInside = require('./utils/is-function-self-used-inside.js');
1616
const {isNodeMatches} = require('./utils/is-node-matches.js');
1717
const assertToken = require('./utils/assert-token.js');
18+
const {fixSpaceAroundKeyword} = require('./fix/index.js');
1819

1920
const MESSAGE_ID = 'no-array-for-each';
2021
const messages = {
@@ -235,6 +236,8 @@ function getFixFunction(callExpression, functionInfo, context) {
235236
yield fixer.remove(expressionStatementLastToken, fixer);
236237
}
237238

239+
yield * fixSpaceAroundKeyword(fixer, callExpression.parent, sourceCode);
240+
238241
// Prevent possible variable conflicts
239242
yield * extendFixRange(fixer, callExpression.parent.range);
240243
};

rules/no-instanceof-array.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22
const {checkVueTemplate} = require('./utils/rule.js');
33
const {getParenthesizedRange} = require('./utils/parentheses.js');
4-
const {replaceNodeOrTokenAndSpacesBefore} = require('./fix/index.js');
4+
const {replaceNodeOrTokenAndSpacesBefore, fixSpaceAroundKeyword} = require('./fix/index.js');
55

66
const isInstanceofToken = token => token.value === 'instanceof' && token.type === 'Keyword';
77

@@ -34,6 +34,8 @@ const create = context => {
3434
messageId: MESSAGE_ID,
3535
/** @param {import('eslint').Rule.RuleFixer} fixer */
3636
* fix(fixer) {
37+
yield * fixSpaceAroundKeyword(fixer, node, sourceCode);
38+
3739
const range = getParenthesizedRange(left, tokenStore);
3840
yield fixer.insertTextBeforeRange(range, 'Array.isArray(');
3941
yield fixer.insertTextAfterRange(range, ')');

rules/no-unreadable-array-destructuring.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22
const {isParenthesized} = require('eslint-utils');
33
const shouldAddParenthesesToMemberExpressionObject = require('./utils/should-add-parentheses-to-member-expression-object.js');
4+
const {fixSpaceAroundKeyword} = require('./fix/index.js');
45

56
const MESSAGE_ID = 'no-unreadable-array-destructuring';
67
const messages = {
@@ -54,6 +55,8 @@ const create = context => {
5455
} else {
5556
yield fixer.insertTextAfter(parent, code);
5657
}
58+
59+
yield * fixSpaceAroundKeyword(fixer, node, sourceCode);
5760
};
5861
}
5962
}

rules/no-useless-spread.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const {
77
} = require('./selectors/index.js');
88
const {getParentheses} = require('./utils/parentheses.js');
99
const typedArray = require('./shared/typed-array.js');
10+
const {fixSpaceAroundKeyword} = require('./fix/index.js');
1011

1112
const SPREAD_IN_LIST = 'spread-in-list';
1213
const ITERABLE_TO_ARRAY = 'iterable-to-array';
@@ -173,6 +174,10 @@ const create = context => {
173174
messageId,
174175
data: {parentDescription},
175176
* fix(fixer) {
177+
if (parent.type === 'ForOfStatement') {
178+
yield * fixSpaceAroundKeyword(fixer, array, sourceCode);
179+
}
180+
176181
const [
177182
openingBracketToken,
178183
spreadToken,

rules/prefer-array-flat.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const needsSemicolon = require('./utils/needs-semicolon.js');
99
const shouldAddParenthesesToMemberExpressionObject = require('./utils/should-add-parentheses-to-member-expression-object.js');
1010
const {isNodeMatches, isNodeMatchesNameOrPath} = require('./utils/is-node-matches.js');
1111
const {getParenthesizedText, isParenthesized} = require('./utils/parentheses.js');
12+
const {fixSpaceAroundKeyword} = require('./fix/index.js');
1213

1314
const MESSAGE_ID = 'prefer-array-flat';
1415
const messages = {
@@ -147,7 +148,7 @@ function fix(node, array, sourceCode, shouldSwitchToArray) {
147148
shouldSwitchToArray = shouldSwitchToArray(node);
148149
}
149150

150-
return fixer => {
151+
return function * (fixer) {
151152
let fixed = getParenthesizedText(array, sourceCode);
152153
if (shouldSwitchToArray) {
153154
// `array` is an argument, when it changes to `array[]`, we don't need add extra parentheses
@@ -167,7 +168,9 @@ function fix(node, array, sourceCode, shouldSwitchToArray) {
167168
fixed = `;${fixed}`;
168169
}
169170

170-
return fixer.replaceText(node, fixed);
171+
yield fixer.replaceText(node, fixed);
172+
173+
yield * fixSpaceAroundKeyword(fixer, node, sourceCode);
171174
};
172175
}
173176

rules/prefer-date-now.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const {
55
newExpressionSelector,
66
callExpressionSelector,
77
} = require('./selectors/index.js');
8+
const {fixSpaceAroundKeyword} = require('./fix/index.js');
89

910
const MESSAGE_ID_DEFAULT = 'prefer-date';
1011
const MESSAGE_ID_METHOD = 'prefer-date-now-over-methods';
@@ -52,14 +53,20 @@ const binaryExpressionSelector = [
5253
newDateSelector,
5354
].join('');
5455

55-
const getProblem = (node, problem) => ({
56+
const getProblem = (node, problem, sourceCode) => ({
5657
node,
5758
messageId: MESSAGE_ID_DEFAULT,
58-
fix: fixer => fixer.replaceText(node, 'Date.now()'),
59+
* fix(fixer) {
60+
yield fixer.replaceText(node, 'Date.now()');
61+
62+
if (node.type === 'UnaryExpression') {
63+
yield * fixSpaceAroundKeyword(fixer, node, sourceCode);
64+
}
65+
},
5966
...problem,
6067
});
6168

62-
const create = () => {
69+
const create = context => {
6370
return {
6471
[methodsSelector](node) {
6572
const method = node.callee.property;
@@ -80,7 +87,11 @@ const create = () => {
8087
return getProblem(node.arguments[0]);
8188
},
8289
[unaryExpressionsSelector](node) {
83-
return getProblem(node.operator === '-' ? node.argument : node);
90+
return getProblem(
91+
node.operator === '-' ? node.argument : node,
92+
{},
93+
context.getSourceCode(),
94+
);
8495
},
8596
[assignmentExpressionSelector](node) {
8697
return getProblem(node);

0 commit comments

Comments
 (0)