Skip to content

Commit 4ee6715

Browse files
committed
Refactored scanJsxToken when is formatting
1 parent 56cf2e6 commit 4ee6715

File tree

7 files changed

+120
-26
lines changed

7 files changed

+120
-26
lines changed

src/compiler/scanner.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ namespace ts {
4040
scanJsxIdentifier(): SyntaxKind;
4141
scanJsxAttributeValue(): SyntaxKind;
4242
reScanJsxAttributeValue(): SyntaxKind;
43-
reScanJsxToken(): JsxTokenSyntaxKind;
43+
reScanJsxToken(isFormatting?: boolean): JsxTokenSyntaxKind;
4444
reScanLessThanToken(): SyntaxKind;
4545
reScanQuestionToken(): SyntaxKind;
4646
reScanInvalidIdentifier(): SyntaxKind;
@@ -2223,9 +2223,9 @@ namespace ts {
22232223
return token = scanTemplateAndSetTokenValue(/* isTaggedTemplate */ true);
22242224
}
22252225

2226-
function reScanJsxToken(): JsxTokenSyntaxKind {
2226+
function reScanJsxToken(isFormatting?: boolean): JsxTokenSyntaxKind {
22272227
pos = tokenPos = startPos;
2228-
return token = scanJsxToken();
2228+
return token = scanJsxToken(isFormatting);
22292229
}
22302230

22312231
function reScanLessThanToken(): SyntaxKind {
@@ -2242,7 +2242,7 @@ namespace ts {
22422242
return token = SyntaxKind.QuestionToken;
22432243
}
22442244

2245-
function scanJsxToken(): JsxTokenSyntaxKind {
2245+
function scanJsxToken(isFormatting?: boolean): JsxTokenSyntaxKind {
22462246
startPos = tokenPos = pos;
22472247

22482248
if (pos >= end) {
@@ -2268,17 +2268,13 @@ namespace ts {
22682268
let firstNonWhitespace = 0;
22692269
let lastNonWhitespace = -1;
22702270

2271+
// Keeps track for the last line break in jsx text.
2272+
let seenLineBreakInJsxText = false;
2273+
22712274
// These initial values are special because the first line is:
22722275
// firstNonWhitespace = 0 to indicate that we want leading whitespace,
22732276

22742277
while (pos < end) {
2275-
2276-
// We want to keep track of the last non-whitespace (but including
2277-
// newlines character for hitting the end of the JSX Text region)
2278-
if (!isWhiteSpaceSingleLine(char)) {
2279-
lastNonWhitespace = pos;
2280-
}
2281-
22822278
char = text.charCodeAt(pos);
22832279
if (char === CharacterCodes.openBrace) {
22842280
break;
@@ -2297,8 +2293,6 @@ namespace ts {
22972293
error(Diagnostics.Unexpected_token_Did_you_mean_or_rbrace, pos, 1);
22982294
}
22992295

2300-
if (lastNonWhitespace > 0) lastNonWhitespace++;
2301-
23022296
// FirstNonWhitespace is 0, then we only see whitespaces so far. If we see a linebreak, we want to ignore that whitespaces.
23032297
// i.e (- : whitespace)
23042298
// <div>----
@@ -2310,14 +2304,35 @@ namespace ts {
23102304
}
23112305
else if (!isWhiteSpaceLike(char)) {
23122306
firstNonWhitespace = pos;
2307+
seenLineBreakInJsxText = false;
23132308
}
23142309

23152310
pos++;
2311+
2312+
// If is not formatting, just continue capturing the non whitespace.
2313+
// Stop JsxText on the last linebreak if it exists otherwise just continue capturing the position.
2314+
if(!isFormatting) {
2315+
lastNonWhitespace = pos;
2316+
}
2317+
else if (firstNonWhitespace > 0 && !seenLineBreakInJsxText) {
2318+
if (isLineBreak(char)) {
2319+
seenLineBreakInJsxText = true;
2320+
}
2321+
else {
2322+
lastNonWhitespace = pos;
2323+
}
2324+
}
23162325
}
23172326

23182327
const endPosition = lastNonWhitespace === -1 ? pos : lastNonWhitespace;
23192328
tokenValue = text.substring(startPos, endPosition);
23202329

2330+
// Update pos if it is rescanning for formatting. This will allow the next node to include
2331+
// all whitespace as trivia instead of being part of jsx text node.
2332+
if(isFormatting) {
2333+
pos = endPosition;
2334+
}
2335+
23212336
return firstNonWhitespace === -1 ? SyntaxKind.JsxTextAllWhiteSpaces : SyntaxKind.JsxText;
23222337
}
23232338

src/services/formatting/formatting.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -759,9 +759,15 @@ namespace ts.formatting {
759759
if (child.kind === SyntaxKind.JsxText) {
760760
const range: TextRange = { pos: child.getStart(), end: child.getEnd() };
761761
if (range.pos !== range.end) { // don't indent zero-width jsx text
762-
const siblings = parent.getChildren(sourceFile);
763-
const currentIndex = findIndex(siblings, arg => arg.pos === child.pos);
764-
const previousNode = siblings[currentIndex - 1];
762+
let tempNode: Node;
763+
let previousNode: Node | undefined;
764+
forEachChild(parent, childNode => {
765+
if (childNode.pos === child.pos) {
766+
previousNode = tempNode;
767+
return true;
768+
}
769+
tempNode = childNode;
770+
});
765771
if (previousNode) {
766772
// The jsx text needs no indentation whatsoever if it ends on the same line the previous sibling ends on
767773
if (sourceFile.getLineAndCharacterOfPosition(range.end).line !== sourceFile.getLineAndCharacterOfPosition(previousNode.end).line) {

src/services/formatting/formattingScanner.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,7 @@ namespace ts.formatting {
124124
}
125125

126126
function shouldRescanJsxText(node: Node): boolean {
127-
const isJSXText = isJsxText(node);
128-
if (isJSXText) {
129-
const containingElement = findAncestor(node.parent, p => isJsxElement(p));
130-
if (!containingElement) return false; // should never happen
131-
return !isParenthesizedExpression(containingElement.parent);
132-
}
133-
return false;
127+
return isJsxText(node);
134128
}
135129

136130
function shouldRescanSlashToken(container: Node): boolean {
@@ -252,7 +246,7 @@ namespace ts.formatting {
252246
return scanner.scanJsxIdentifier();
253247
case ScanAction.RescanJsxText:
254248
lastScanAction = ScanAction.RescanJsxText;
255-
return scanner.reScanJsxToken();
249+
return scanner.reScanJsxToken(/* isFormatting */ true);
256250
case ScanAction.RescanJsxAttributeValue:
257251
lastScanAction = ScanAction.RescanJsxAttributeValue;
258252
return scanner.reScanJsxAttributeValue();

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3967,7 +3967,7 @@ declare namespace ts {
39673967
scanJsxIdentifier(): SyntaxKind;
39683968
scanJsxAttributeValue(): SyntaxKind;
39693969
reScanJsxAttributeValue(): SyntaxKind;
3970-
reScanJsxToken(): JsxTokenSyntaxKind;
3970+
reScanJsxToken(isFormatting?: boolean): JsxTokenSyntaxKind;
39713971
reScanLessThanToken(): SyntaxKind;
39723972
reScanQuestionToken(): SyntaxKind;
39733973
reScanInvalidIdentifier(): SyntaxKind;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3967,7 +3967,7 @@ declare namespace ts {
39673967
scanJsxIdentifier(): SyntaxKind;
39683968
scanJsxAttributeValue(): SyntaxKind;
39693969
reScanJsxAttributeValue(): SyntaxKind;
3970-
reScanJsxToken(): JsxTokenSyntaxKind;
3970+
reScanJsxToken(isFormatting?: boolean): JsxTokenSyntaxKind;
39713971
reScanLessThanToken(): SyntaxKind;
39723972
reScanQuestionToken(): SyntaxKind;
39733973
reScanInvalidIdentifier(): SyntaxKind;
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//@Filename: file.tsx
4+
//// const a = (
5+
//// <div>
6+
//// foo
7+
//// </div>
8+
//// );
9+
////
10+
//// const b = (
11+
//// <div>
12+
//// { foo }
13+
//// </div>
14+
//// );
15+
////
16+
//// const c = (
17+
//// <div>
18+
//// foo
19+
//// { foobar }
20+
//// bar
21+
//// </div>
22+
//// );
23+
////
24+
//// const d =
25+
//// <div>
26+
//// foo
27+
//// </div>;
28+
////
29+
//// const e =
30+
//// <div>
31+
//// { foo }
32+
//// </div>
33+
////
34+
//// const f =
35+
//// <div>
36+
//// foo
37+
//// { foobar }
38+
//// bar
39+
//// </div>
40+
41+
format.document();
42+
43+
verify.currentFileContentIs(
44+
`const a = (
45+
<div>
46+
foo
47+
</div>
48+
);
49+
50+
const b = (
51+
<div>
52+
{foo}
53+
</div>
54+
);
55+
56+
const c = (
57+
<div>
58+
foo
59+
{foobar}
60+
bar
61+
</div>
62+
);
63+
64+
const d =
65+
<div>
66+
foo
67+
</div>;
68+
69+
const e =
70+
<div>
71+
{foo}
72+
</div>
73+
74+
const f =
75+
<div>
76+
foo
77+
{foobar}
78+
bar
79+
</div>`);

0 commit comments

Comments
 (0)