Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit bc435a9

Browse filesBrowse files
mysticateaKai Cataldo
authored andcommitted
Fix: isSpaceBetweenTokens() recognizes spaces in JSXText (fixes #12614) (#12616)
* Fix: isSpaceBetween() recognizes spaces in JSXText (fixes #12614) * apply this fix only for isSpaceBetweenTokens() * move tests to the section for nodes * add tests for isSpaceBetween() * add tests for reversed order
1 parent 4928d51 commit bc435a9
Copy full SHA for bc435a9

File tree

Expand file treeCollapse file tree

2 files changed

+183
-25
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+183
-25
lines changed
Open diff view settings
Collapse file

‎lib/source-code/source-code.js‎

Copy file name to clipboardExpand all lines: lib/source-code/source-code.js
+57-25Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,56 @@ function nodesOrTokensOverlap(first, second) {
9090
(second.range[0] <= first.range[0] && second.range[1] >= first.range[0]);
9191
}
9292

93+
/**
94+
* Determines if two nodes or tokens have at least one whitespace character
95+
* between them. Order does not matter. Returns false if the given nodes or
96+
* tokens overlap.
97+
* @param {SourceCode} sourceCode The source code object.
98+
* @param {ASTNode|Token} first The first node or token to check between.
99+
* @param {ASTNode|Token} second The second node or token to check between.
100+
* @param {boolean} checkInsideOfJSXText If `true` is present, check inside of JSXText tokens for backward compatibility.
101+
* @returns {boolean} True if there is a whitespace character between
102+
* any of the tokens found between the two given nodes or tokens.
103+
* @public
104+
*/
105+
function isSpaceBetween(sourceCode, first, second, checkInsideOfJSXText) {
106+
if (nodesOrTokensOverlap(first, second)) {
107+
return false;
108+
}
109+
110+
const [startingNodeOrToken, endingNodeOrToken] = first.range[1] <= second.range[0]
111+
? [first, second]
112+
: [second, first];
113+
const firstToken = sourceCode.getLastToken(startingNodeOrToken) || startingNodeOrToken;
114+
const finalToken = sourceCode.getFirstToken(endingNodeOrToken) || endingNodeOrToken;
115+
let currentToken = firstToken;
116+
117+
while (currentToken !== finalToken) {
118+
const nextToken = sourceCode.getTokenAfter(currentToken, { includeComments: true });
119+
120+
if (
121+
currentToken.range[1] !== nextToken.range[0] ||
122+
123+
/*
124+
* For backward compatibility, check speces in JSXText.
125+
* https://github.com/eslint/eslint/issues/12614
126+
*/
127+
(
128+
checkInsideOfJSXText &&
129+
nextToken !== finalToken &&
130+
nextToken.type === "JSXText" &&
131+
/\s/u.test(nextToken.value)
132+
)
133+
) {
134+
return true;
135+
}
136+
137+
currentToken = nextToken;
138+
}
139+
140+
return false;
141+
}
142+
93143
//------------------------------------------------------------------------------
94144
// Public Interface
95145
//------------------------------------------------------------------------------
@@ -433,42 +483,24 @@ class SourceCode extends TokenStore {
433483
* @public
434484
*/
435485
isSpaceBetween(first, second) {
436-
if (nodesOrTokensOverlap(first, second)) {
437-
return false;
438-
}
439-
440-
const [startingNodeOrToken, endingNodeOrToken] = first.range[1] <= second.range[0]
441-
? [first, second]
442-
: [second, first];
443-
const firstToken = this.getLastToken(startingNodeOrToken) || startingNodeOrToken;
444-
const finalToken = this.getFirstToken(endingNodeOrToken) || endingNodeOrToken;
445-
let currentToken = firstToken;
446-
447-
while (currentToken !== finalToken) {
448-
const nextToken = this.getTokenAfter(currentToken, { includeComments: true });
449-
450-
if (currentToken.range[1] !== nextToken.range[0]) {
451-
return true;
452-
}
453-
454-
currentToken = nextToken;
455-
}
456-
457-
return false;
486+
return isSpaceBetween(this, first, second, false);
458487
}
459488

460489
/**
461490
* Determines if two nodes or tokens have at least one whitespace character
462491
* between them. Order does not matter. Returns false if the given nodes or
463492
* tokens overlap.
464-
* @param {...ASTNode|Token} args The nodes or tokens to check between.
493+
* For backward compatibility, this method returns true if there are
494+
* `JSXText` tokens that contain whitespaces between the two.
495+
* @param {ASTNode|Token} first The first node or token to check between.
496+
* @param {ASTNode|Token} second The second node or token to check between.
465497
* @returns {boolean} True if there is a whitespace character between
466498
* any of the tokens found between the two given nodes or tokens.
467499
* @deprecated in favor of isSpaceBetween().
468500
* @public
469501
*/
470-
isSpaceBetweenTokens(...args) {
471-
return this.isSpaceBetween(...args);
502+
isSpaceBetweenTokens(first, second) {
503+
return isSpaceBetween(this, first, second, true);
472504
}
473505

474506
/**
Collapse file

‎tests/lib/source-code/source-code.js‎

Copy file name to clipboardExpand all lines: tests/lib/source-code/source-code.js
+126Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2076,6 +2076,69 @@ describe("SourceCode", () => {
20762076
});
20772077
});
20782078
});
2079+
2080+
it("JSXText tokens that contain only whitespaces should NOT be handled as space", () => {
2081+
const code = "let jsx = <div>\n {content}\n</div>";
2082+
const ast = espree.parse(code, { ...DEFAULT_CONFIG, ecmaFeatures: { jsx: true } });
2083+
const sourceCode = new SourceCode(code, ast);
2084+
const jsx = ast.body[0].declarations[0].init;
2085+
const interpolation = jsx.children[1];
2086+
2087+
assert.strictEqual(
2088+
sourceCode.isSpaceBetween(jsx.openingElement, interpolation),
2089+
false
2090+
);
2091+
assert.strictEqual(
2092+
sourceCode.isSpaceBetween(interpolation, jsx.closingElement),
2093+
false
2094+
);
2095+
2096+
// Reversed order
2097+
assert.strictEqual(
2098+
sourceCode.isSpaceBetween(interpolation, jsx.openingElement),
2099+
false
2100+
);
2101+
assert.strictEqual(
2102+
sourceCode.isSpaceBetween(jsx.closingElement, interpolation),
2103+
false
2104+
);
2105+
});
2106+
2107+
it("JSXText tokens that contain both letters and whitespaces should NOT be handled as space", () => {
2108+
const code = "let jsx = <div>\n Hello\n</div>";
2109+
const ast = espree.parse(code, { ...DEFAULT_CONFIG, ecmaFeatures: { jsx: true } });
2110+
const sourceCode = new SourceCode(code, ast);
2111+
const jsx = ast.body[0].declarations[0].init;
2112+
2113+
assert.strictEqual(
2114+
sourceCode.isSpaceBetween(jsx.openingElement, jsx.closingElement),
2115+
false
2116+
);
2117+
2118+
// Reversed order
2119+
assert.strictEqual(
2120+
sourceCode.isSpaceBetween(jsx.closingElement, jsx.openingElement),
2121+
false
2122+
);
2123+
});
2124+
2125+
it("JSXText tokens that contain only letters should NOT be handled as space", () => {
2126+
const code = "let jsx = <div>Hello</div>";
2127+
const ast = espree.parse(code, { ...DEFAULT_CONFIG, ecmaFeatures: { jsx: true } });
2128+
const sourceCode = new SourceCode(code, ast);
2129+
const jsx = ast.body[0].declarations[0].init;
2130+
2131+
assert.strictEqual(
2132+
sourceCode.isSpaceBetween(jsx.openingElement, jsx.closingElement),
2133+
false
2134+
);
2135+
2136+
// Reversed order
2137+
assert.strictEqual(
2138+
sourceCode.isSpaceBetween(jsx.closingElement, jsx.openingElement),
2139+
false
2140+
);
2141+
});
20792142
});
20802143

20812144
describe("should return false either of the arguments' location is inside the other one", () => {
@@ -2409,6 +2472,69 @@ describe("SourceCode", () => {
24092472
});
24102473
});
24112474
});
2475+
2476+
it("JSXText tokens that contain only whitespaces should be handled as space", () => {
2477+
const code = "let jsx = <div>\n {content}\n</div>";
2478+
const ast = espree.parse(code, { ...DEFAULT_CONFIG, ecmaFeatures: { jsx: true } });
2479+
const sourceCode = new SourceCode(code, ast);
2480+
const jsx = ast.body[0].declarations[0].init;
2481+
const interpolation = jsx.children[1];
2482+
2483+
assert.strictEqual(
2484+
sourceCode.isSpaceBetweenTokens(jsx.openingElement, interpolation),
2485+
true
2486+
);
2487+
assert.strictEqual(
2488+
sourceCode.isSpaceBetweenTokens(interpolation, jsx.closingElement),
2489+
true
2490+
);
2491+
2492+
// Reversed order
2493+
assert.strictEqual(
2494+
sourceCode.isSpaceBetweenTokens(interpolation, jsx.openingElement),
2495+
true
2496+
);
2497+
assert.strictEqual(
2498+
sourceCode.isSpaceBetweenTokens(jsx.closingElement, interpolation),
2499+
true
2500+
);
2501+
});
2502+
2503+
it("JSXText tokens that contain both letters and whitespaces should be handled as space", () => {
2504+
const code = "let jsx = <div>\n Hello\n</div>";
2505+
const ast = espree.parse(code, { ...DEFAULT_CONFIG, ecmaFeatures: { jsx: true } });
2506+
const sourceCode = new SourceCode(code, ast);
2507+
const jsx = ast.body[0].declarations[0].init;
2508+
2509+
assert.strictEqual(
2510+
sourceCode.isSpaceBetweenTokens(jsx.openingElement, jsx.closingElement),
2511+
true
2512+
);
2513+
2514+
// Reversed order
2515+
assert.strictEqual(
2516+
sourceCode.isSpaceBetweenTokens(jsx.closingElement, jsx.openingElement),
2517+
true
2518+
);
2519+
});
2520+
2521+
it("JSXText tokens that contain only letters should NOT be handled as space", () => {
2522+
const code = "let jsx = <div>Hello</div>";
2523+
const ast = espree.parse(code, { ...DEFAULT_CONFIG, ecmaFeatures: { jsx: true } });
2524+
const sourceCode = new SourceCode(code, ast);
2525+
const jsx = ast.body[0].declarations[0].init;
2526+
2527+
assert.strictEqual(
2528+
sourceCode.isSpaceBetweenTokens(jsx.openingElement, jsx.closingElement),
2529+
false
2530+
);
2531+
2532+
// Reversed order
2533+
assert.strictEqual(
2534+
sourceCode.isSpaceBetweenTokens(jsx.closingElement, jsx.openingElement),
2535+
false
2536+
);
2537+
});
24122538
});
24132539

24142540
describe("should return false either of the arguments' location is inside the other one", () => {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.