Skip to content

Commit 60df467

Browse files
authored
Fix jsx element parsing within ternary (microsoft#24149)
1 parent 62921d5 commit 60df467

File tree

5 files changed

+122
-7
lines changed

5 files changed

+122
-7
lines changed

src/compiler/parser.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2436,20 +2436,24 @@ namespace ts {
24362436
return finishNode(node);
24372437
}
24382438

2439+
/**
2440+
* @returns If return type parsing succeeds
2441+
*/
24392442
function fillSignature(
24402443
returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken,
24412444
flags: SignatureFlags,
2442-
signature: SignatureDeclaration): void {
2445+
signature: SignatureDeclaration): boolean {
24432446
if (!(flags & SignatureFlags.JSDoc)) {
24442447
signature.typeParameters = parseTypeParameters();
24452448
}
24462449
signature.parameters = parseParameterList(flags);
2447-
signature.type = parseReturnType(returnToken, !!(flags & SignatureFlags.Type));
2450+
if (shouldParseReturnType(returnToken, !!(flags & SignatureFlags.Type))) {
2451+
signature.type = parseTypeOrTypePredicate();
2452+
return signature.type !== undefined;
2453+
}
2454+
return true;
24482455
}
24492456

2450-
function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined {
2451-
return shouldParseReturnType(returnToken, isType) ? parseTypeOrTypePredicate() : undefined;
2452-
}
24532457
function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean {
24542458
if (returnToken === SyntaxKind.EqualsGreaterThanToken) {
24552459
parseExpected(returnToken);
@@ -2758,6 +2762,9 @@ namespace ts {
27582762
const node = <ParenthesizedTypeNode>createNode(SyntaxKind.ParenthesizedType);
27592763
parseExpected(SyntaxKind.OpenParenToken);
27602764
node.type = parseType();
2765+
if (!node.type) {
2766+
return undefined;
2767+
}
27612768
parseExpected(SyntaxKind.CloseParenToken);
27622769
return finishNode(node);
27632770
}
@@ -2767,7 +2774,12 @@ namespace ts {
27672774
if (kind === SyntaxKind.ConstructorType) {
27682775
parseExpected(SyntaxKind.NewKeyword);
27692776
}
2770-
fillSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type, node);
2777+
if (!fillSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type | (sourceFile.languageVariant === LanguageVariant.JSX ? SignatureFlags.RequireCompleteParameterList : 0), node)) {
2778+
return undefined;
2779+
}
2780+
if (!node.parameters) {
2781+
return undefined;
2782+
}
27712783
return finishNode(node);
27722784
}
27732785

@@ -3598,7 +3610,9 @@ namespace ts {
35983610
// a => (b => c)
35993611
// And think that "(b =>" was actually a parenthesized arrow function with a missing
36003612
// close paren.
3601-
fillSignature(SyntaxKind.ColonToken, isAsync | (allowAmbiguity ? SignatureFlags.None : SignatureFlags.RequireCompleteParameterList), node);
3613+
if (!fillSignature(SyntaxKind.ColonToken, isAsync | (allowAmbiguity ? SignatureFlags.None : SignatureFlags.RequireCompleteParameterList), node)) {
3614+
return undefined;
3615+
}
36023616

36033617
// If we couldn't get parameters, we definitely could not parse out an arrow function.
36043618
if (!node.parameters) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [jsxNestedWithinTernaryParsesCorrectly.tsx]
2+
const emptyMessage = null as any;
3+
const a = (
4+
<div>
5+
{0 ? (
6+
emptyMessage // must be identifier?
7+
) : (
8+
// must be exactly two expression holes
9+
<span>
10+
{0}{0}
11+
</span>
12+
)}
13+
</div>
14+
);
15+
16+
//// [jsxNestedWithinTernaryParsesCorrectly.jsx]
17+
var emptyMessage = null;
18+
var a = (<div>
19+
{0 ? (emptyMessage // must be identifier?
20+
) : (
21+
// must be exactly two expression holes
22+
<span>
23+
{0}{0}
24+
</span>)}
25+
</div>);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/compiler/jsxNestedWithinTernaryParsesCorrectly.tsx ===
2+
const emptyMessage = null as any;
3+
>emptyMessage : Symbol(emptyMessage, Decl(jsxNestedWithinTernaryParsesCorrectly.tsx, 0, 5))
4+
5+
const a = (
6+
>a : Symbol(a, Decl(jsxNestedWithinTernaryParsesCorrectly.tsx, 1, 5))
7+
8+
<div>
9+
{0 ? (
10+
emptyMessage // must be identifier?
11+
>emptyMessage : Symbol(emptyMessage, Decl(jsxNestedWithinTernaryParsesCorrectly.tsx, 0, 5))
12+
13+
) : (
14+
// must be exactly two expression holes
15+
<span>
16+
{0}{0}
17+
</span>
18+
)}
19+
</div>
20+
);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
=== tests/cases/compiler/jsxNestedWithinTernaryParsesCorrectly.tsx ===
2+
const emptyMessage = null as any;
3+
>emptyMessage : any
4+
>null as any : any
5+
>null : null
6+
7+
const a = (
8+
>a : any
9+
>( <div> {0 ? ( emptyMessage // must be identifier? ) : ( // must be exactly two expression holes <span> {0}{0} </span> )} </div>) : any
10+
11+
<div>
12+
><div> {0 ? ( emptyMessage // must be identifier? ) : ( // must be exactly two expression holes <span> {0}{0} </span> )} </div> : any
13+
>div : any
14+
15+
{0 ? (
16+
>0 ? ( emptyMessage // must be identifier? ) : ( // must be exactly two expression holes <span> {0}{0} </span> ) : any
17+
>0 : 0
18+
>( emptyMessage // must be identifier? ) : any
19+
20+
emptyMessage // must be identifier?
21+
>emptyMessage : any
22+
23+
) : (
24+
>( // must be exactly two expression holes <span> {0}{0} </span> ) : any
25+
26+
// must be exactly two expression holes
27+
<span>
28+
><span> {0}{0} </span> : any
29+
>span : any
30+
31+
{0}{0}
32+
>0 : 0
33+
>0 : 0
34+
35+
</span>
36+
>span : any
37+
38+
)}
39+
</div>
40+
>div : any
41+
42+
);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @jsx: preserve
2+
const emptyMessage = null as any;
3+
const a = (
4+
<div>
5+
{0 ? (
6+
emptyMessage // must be identifier?
7+
) : (
8+
// must be exactly two expression holes
9+
<span>
10+
{0}{0}
11+
</span>
12+
)}
13+
</div>
14+
);

0 commit comments

Comments
 (0)