Skip to content

Commit 62c2dd0

Browse files
committed
move isSpaceBetween to util
1 parent 26a62bb commit 62c2dd0

6 files changed

Lines changed: 148 additions & 40 deletions

File tree

lib/rules/jsx-curly-spacing.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
const docsUrl = require('../util/docsUrl');
1515
const getSourceCode = require('../util/eslint').getSourceCode;
16+
const isSpaceBetween = require('../util/eslint').isSpaceBetween;
1617
const report = require('../util/report');
1718

1819
// ------------------------------------------------------------------------------
@@ -391,12 +392,12 @@ module.exports = {
391392
const isObjectLiteral = first.value === second.value;
392393
const spacing = isObjectLiteral ? config.objectLiteralSpaces : config.when;
393394
if (spacing === SPACING.always) {
394-
if (!sourceCode.isSpaceBetween(first, second)) {
395+
if (!isSpaceBetween(context, first, second)) {
395396
reportRequiredBeginningSpace(node, first);
396397
} else if (!config.allowMultiline && isMultiline(first, second)) {
397398
reportNoBeginningNewline(node, first, spacing);
398399
}
399-
if (!sourceCode.isSpaceBetween(penultimate, last)) {
400+
if (!isSpaceBetween(context, penultimate, last)) {
400401
reportRequiredEndingSpace(node, last);
401402
} else if (!config.allowMultiline && isMultiline(penultimate, last)) {
402403
reportNoEndingNewline(node, last, spacing);
@@ -406,14 +407,14 @@ module.exports = {
406407
if (!config.allowMultiline) {
407408
reportNoBeginningNewline(node, first, spacing);
408409
}
409-
} else if (sourceCode.isSpaceBetween(first, second)) {
410+
} else if (isSpaceBetween(context, first, second)) {
410411
reportNoBeginningSpace(node, first);
411412
}
412413
if (isMultiline(penultimate, last)) {
413414
if (!config.allowMultiline) {
414415
reportNoEndingNewline(node, last, spacing);
415416
}
416-
} else if (sourceCode.isSpaceBetween(penultimate, last)) {
417+
} else if (isSpaceBetween(context, penultimate, last)) {
417418
reportNoEndingSpace(node, last);
418419
}
419420
}

lib/rules/jsx-equals-spacing.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
const docsUrl = require('../util/docsUrl');
99
const getSourceCode = require('../util/eslint').getSourceCode;
10+
const isSpaceBetween = require('../util/eslint').isSpaceBetween;
1011
const report = require('../util/report');
1112

1213
// ------------------------------------------------------------------------------
@@ -63,8 +64,8 @@ module.exports = {
6364

6465
const sourceCode = getSourceCode(context);
6566
const equalToken = sourceCode.getTokenAfter(attrNode.name);
66-
const spacedBefore = sourceCode.isSpaceBetween(attrNode.name, equalToken);
67-
const spacedAfter = sourceCode.isSpaceBetween(equalToken, attrNode.value);
67+
const spacedBefore = isSpaceBetween(context, attrNode.name, equalToken);
68+
const spacedAfter = isSpaceBetween(context, equalToken, attrNode.value);
6869

6970
if (config === 'never') {
7071
if (spacedBefore) {

lib/rules/jsx-one-expression-per-line.js

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ const eslintUtil = require('../util/eslint');
1010
const jsxUtil = require('../util/jsx');
1111
const report = require('../util/report');
1212

13-
const getSourceCode = eslintUtil.getSourceCode;
1413
const getText = eslintUtil.getText;
14+
const isSpaceBetween = eslintUtil.isSpaceBetween;
1515

1616
// ------------------------------------------------------------------------------
1717
// Rule Definition
@@ -87,30 +87,6 @@ module.exports = {
8787
const openingElementEndLine = openingElement.loc.end.line;
8888
const closingElementStartLine = closingElement.loc.start.line;
8989
const closingElementEndLine = closingElement.loc.end.line;
90-
const sourceCode = getSourceCode(context);
91-
92-
/**
93-
* Like SourceCode#isSpaceBetween, but also works when the "space" is a
94-
* token (e.g. JSXText).
95-
* @param {ASTNode|import('eslint').AST.Token} first
96-
* @param {ASTNode|import('eslint').AST.Token} second
97-
* @returns {boolean}
98-
*/
99-
function hasSpaceBetween(first, second) {
100-
if (!first || !second) {
101-
return false;
102-
}
103-
104-
if (first.range[0] < second.range[1] && second.range[0] < first.range[1]) {
105-
return false;
106-
}
107-
108-
const [startingNodeOrToken, endingNodeOrToken] = first.range[1] <= second.range[0]
109-
? [first, second]
110-
: [second, first];
111-
112-
return /\s/.test(sourceCode.text.slice(startingNodeOrToken.range[1], endingNodeOrToken.range[0]));
113-
}
11490

11591
if (children.length === 1) {
11692
const child = children[0];
@@ -195,13 +171,13 @@ module.exports = {
195171
function spaceBetweenPrev() {
196172
return ((prevChild.type === 'Literal' || prevChild.type === 'JSXText') && / $/.test(prevChild.raw))
197173
|| ((child.type === 'Literal' || child.type === 'JSXText') && /^ /.test(child.raw))
198-
|| hasSpaceBetween(prevChild, child);
174+
|| isSpaceBetween(context, prevChild, child);
199175
}
200176

201177
function spaceBetweenNext() {
202178
return ((nextChild.type === 'Literal' || nextChild.type === 'JSXText') && /^ /.test(nextChild.raw))
203179
|| ((child.type === 'Literal' || child.type === 'JSXText') && / $/.test(child.raw))
204-
|| hasSpaceBetween(child, nextChild);
180+
|| isSpaceBetween(context, child, nextChild);
205181
}
206182

207183
if (!prevChild && !nextChild) {

lib/rules/jsx-space-before-closing.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const docsUrl = require('../util/docsUrl');
1111
const log = require('../util/log');
1212
const report = require('../util/report');
1313
const getSourceCode = require('../util/eslint').getSourceCode;
14+
const isSpaceBetween = require('../util/eslint').isSpaceBetween;
1415

1516
let isWarnedForDeprecation = false;
1617

@@ -66,14 +67,14 @@ module.exports = {
6667
return;
6768
}
6869

69-
if (configuration === 'always' && !sourceCode.isSpaceBetween(leftToken, closingSlash)) {
70+
if (configuration === 'always' && !isSpaceBetween(context, leftToken, closingSlash)) {
7071
report(context, messages.needSpaceBeforeClose, 'needSpaceBeforeClose', {
7172
loc: closingSlash.loc.start,
7273
fix(fixer) {
7374
return fixer.insertTextBefore(closingSlash, ' ');
7475
},
7576
});
76-
} else if (configuration === 'never' && sourceCode.isSpaceBetween(leftToken, closingSlash)) {
77+
} else if (configuration === 'never' && isSpaceBetween(context, leftToken, closingSlash)) {
7778
report(context, messages.noSpaceBeforeClose, 'noSpaceBeforeClose', {
7879
loc: closingSlash.loc.start,
7980
fix(fixer) {

lib/rules/jsx-tag-spacing.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const eslintUtil = require('../util/eslint');
1212

1313
const getFirstTokens = eslintUtil.getFirstTokens;
1414
const getSourceCode = eslintUtil.getSourceCode;
15+
const isSpaceBetween = eslintUtil.isSpaceBetween;
1516

1617
const messages = {
1718
selfCloseSlashNoSpace: 'Whitespace is forbidden between `/` and `>`; write `/>`',
@@ -40,7 +41,7 @@ function validateClosingSlash(context, node, option) {
4041
if (node.selfClosing) {
4142
const lastTokens = sourceCode.getLastTokens(node, 2);
4243

43-
adjacent = !sourceCode.isSpaceBetween(lastTokens[0], lastTokens[1]);
44+
adjacent = !isSpaceBetween(context, lastTokens[0], lastTokens[1]);
4445

4546
if (option === 'never') {
4647
if (!adjacent) {
@@ -70,7 +71,7 @@ function validateClosingSlash(context, node, option) {
7071
} else {
7172
const firstTokens = getFirstTokens(context, node, 2);
7273

73-
adjacent = !sourceCode.isSpaceBetween(firstTokens[0], firstTokens[1]);
74+
adjacent = !isSpaceBetween(context, firstTokens[0], firstTokens[1]);
7475

7576
if (option === 'never') {
7677
if (!adjacent) {
@@ -122,7 +123,7 @@ function validateBeforeSelfClosing(context, node, option) {
122123
return;
123124
}
124125

125-
const adjacent = !sourceCode.isSpaceBetween(leftToken, closingSlash);
126+
const adjacent = !isSpaceBetween(context, leftToken, closingSlash);
126127

127128
if ((option === 'always' || option === 'proportional-always') && adjacent) {
128129
report(context, messages.beforeSelfCloseNeedSpace, 'beforeSelfCloseNeedSpace', {
@@ -154,7 +155,7 @@ function validateAfterOpening(context, node, option) {
154155
}
155156
}
156157

157-
const adjacent = !sourceCode.isSpaceBetween(openingToken, node.name);
158+
const adjacent = !isSpaceBetween(context, openingToken, node.name);
158159

159160
if (option === 'never' || option === 'allow-multiline') {
160161
if (!adjacent) {
@@ -209,7 +210,7 @@ function validateBeforeClosing(context, node, option) {
209210
return;
210211
}
211212

212-
const adjacent = !sourceCode.isSpaceBetween(leftToken, closingToken);
213+
const adjacent = !isSpaceBetween(context, leftToken, closingToken);
213214

214215
if (option === 'never' && !adjacent) {
215216
report(context, messages.beforeCloseNoSpace, 'beforeCloseNoSpace', {

lib/util/eslint.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,132 @@ function getText(context, ...args) {
3939
return sourceCode.getText ? sourceCode.getText(...args) : context.getSource(...args);
4040
}
4141

42+
function getFirstTokenOrSelf(sourceCode, nodeOrToken) {
43+
if (!nodeOrToken) {
44+
return null;
45+
}
46+
47+
try {
48+
return sourceCode.getFirstToken(nodeOrToken) || nodeOrToken;
49+
} catch {
50+
return nodeOrToken;
51+
}
52+
}
53+
54+
function getLastTokenOrSelf(sourceCode, nodeOrToken) {
55+
if (!nodeOrToken) {
56+
return null;
57+
}
58+
59+
try {
60+
return sourceCode.getLastToken(nodeOrToken) || nodeOrToken;
61+
} catch {
62+
return nodeOrToken;
63+
}
64+
}
65+
66+
function hasWhitespaceInToken(token) {
67+
return token
68+
&& token.type === 'JSXText'
69+
&& typeof token.value === 'string'
70+
&& token.value.trim() === ''
71+
&& /\s/u.test(token.value);
72+
}
73+
74+
function hasWhitespaceTokenBetween(sourceCode, firstNodeOrToken, secondNodeOrToken) {
75+
const firstToken = getLastTokenOrSelf(sourceCode, firstNodeOrToken);
76+
const finalToken = getFirstTokenOrSelf(sourceCode, secondNodeOrToken);
77+
78+
let currentToken = firstToken;
79+
while (currentToken && currentToken !== finalToken) {
80+
const nextToken = sourceCode.getTokenAfter(currentToken, { includeComments: true });
81+
82+
if (!nextToken) {
83+
return false;
84+
}
85+
86+
if (hasWhitespaceInToken(nextToken)) {
87+
return true;
88+
}
89+
90+
currentToken = nextToken;
91+
}
92+
93+
return false;
94+
}
95+
96+
function isSpaceBetweenTokens(context, firstToken, secondToken) {
97+
const sourceCode = getSourceCode(context);
98+
99+
if (!firstToken || !secondToken) {
100+
return false;
101+
}
102+
103+
if (
104+
firstToken.range
105+
&& secondToken.range
106+
&& firstToken.range[0] < secondToken.range[1]
107+
&& secondToken.range[0] < firstToken.range[1]
108+
) {
109+
return false;
110+
}
111+
112+
let first = firstToken;
113+
let second = secondToken;
114+
115+
// Order does not matter, but the SourceCode APIs generally assume it does.
116+
if (first.range && second.range && first.range[1] > second.range[0]) {
117+
[first, second] = [second, first];
118+
}
119+
120+
// ESLint v10+ provides `isSpaceBetween`. Older versions used `isSpaceBetweenTokens`.
121+
if (typeof sourceCode.isSpaceBetweenTokens === 'function') {
122+
return sourceCode.isSpaceBetweenTokens(first, second);
123+
}
124+
if (typeof sourceCode.isSpaceBetween === 'function') {
125+
return sourceCode.isSpaceBetween(first, second) || hasWhitespaceTokenBetween(sourceCode, first, second);
126+
}
127+
128+
if (!first.range || !second.range) {
129+
return false;
130+
}
131+
132+
return /\s/u.test(sourceCode.text.slice(first.range[1], second.range[0]));
133+
}
134+
135+
function isSpaceBetween(context, firstNodeOrToken, secondNodeOrToken) {
136+
const sourceCode = getSourceCode(context);
137+
138+
if (!firstNodeOrToken || !secondNodeOrToken) {
139+
return false;
140+
}
141+
142+
if (
143+
firstNodeOrToken.range
144+
&& secondNodeOrToken.range
145+
&& firstNodeOrToken.range[0] < secondNodeOrToken.range[1]
146+
&& secondNodeOrToken.range[0] < firstNodeOrToken.range[1]
147+
) {
148+
return false;
149+
}
150+
151+
let first = firstNodeOrToken;
152+
let second = secondNodeOrToken;
153+
154+
// Order does not matter, but the SourceCode APIs generally assume it does.
155+
if (first.range && second.range && first.range[1] > second.range[0]) {
156+
[first, second] = [second, first];
157+
}
158+
159+
if (typeof sourceCode.isSpaceBetween === 'function') {
160+
return sourceCode.isSpaceBetween(first, second) || hasWhitespaceTokenBetween(sourceCode, first, second);
161+
}
162+
163+
const firstToken = getLastTokenOrSelf(sourceCode, first);
164+
const secondToken = getFirstTokenOrSelf(sourceCode, second);
165+
return isSpaceBetweenTokens(context, firstToken, secondToken);
166+
}
167+
42168
function getJSDocComment(context, node) {
43169
const sourceCode = getSourceCode(context);
44170

@@ -70,5 +196,7 @@ module.exports = {
70196
getScope,
71197
getSourceCode,
72198
getText,
199+
isSpaceBetween,
200+
isSpaceBetweenTokens,
73201
markVariableAsUsed,
74202
};

0 commit comments

Comments
 (0)