Skip to content

Commit a83ce33

Browse files
Fix poor error span for unclosed JSX tags in the presence of whitespace/comments (microsoft#37419)
* Improve jsx tag error span * Move solution to parseJsxChild func * Add tests and update baselines * Update comment in src/compiler/parser.ts Co-Authored-By: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> * Use skipTrivia to check for whitespaces and other trivia * Import React into errorSpanForUnclosedJsxTag.tsx * . * . Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
1 parent e2156a1 commit a83ce33

6 files changed

+113
-1
lines changed

src/compiler/parser.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -4545,7 +4545,11 @@ namespace ts {
45454545
parseErrorAtRange(openingTag, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag);
45464546
}
45474547
else {
4548-
parseErrorAtRange(openingTag.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName));
4548+
// We want the error span to cover only 'Foo.Bar' in < Foo.Bar >
4549+
// or to cover only 'Foo' in < Foo >
4550+
const tag = openingTag.tagName;
4551+
const start = skipTrivia(sourceText, tag.pos);
4552+
parseErrorAt(start, tag.end, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName));
45494553
}
45504554
return undefined;
45514555
case SyntaxKind.LessThanSlashToken:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
tests/cases/compiler/errorSpanForUnclosedJsxTag.tsx(9,14): error TS17008: JSX element 'Foo.Bar' has no corresponding closing tag.
2+
tests/cases/compiler/errorSpanForUnclosedJsxTag.tsx(11,13): error TS17008: JSX element 'Baz' has no corresponding closing tag.
3+
tests/cases/compiler/errorSpanForUnclosedJsxTag.tsx(11,23): error TS1005: '</' expected.
4+
5+
6+
==== tests/cases/compiler/errorSpanForUnclosedJsxTag.tsx (3 errors) ====
7+
declare const React: any
8+
9+
let Foo = {
10+
Bar() {}
11+
}
12+
13+
let Baz = () => {}
14+
15+
let x = < Foo.Bar >Hello
16+
~~~~~~~
17+
!!! error TS17008: JSX element 'Foo.Bar' has no corresponding closing tag.
18+
19+
let y = < Baz >Hello
20+
~~~
21+
!!! error TS17008: JSX element 'Baz' has no corresponding closing tag.
22+
23+
!!! error TS1005: '</' expected.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [errorSpanForUnclosedJsxTag.tsx]
2+
declare const React: any
3+
4+
let Foo = {
5+
Bar() {}
6+
}
7+
8+
let Baz = () => {}
9+
10+
let x = < Foo.Bar >Hello
11+
12+
let y = < Baz >Hello
13+
14+
//// [errorSpanForUnclosedJsxTag.js]
15+
var Foo = {
16+
Bar: function () { }
17+
};
18+
var Baz = function () { };
19+
var x = React.createElement(Foo.Bar, null,
20+
"Hello let y = ",
21+
React.createElement(Baz, null, "Hello"));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/compiler/errorSpanForUnclosedJsxTag.tsx ===
2+
declare const React: any
3+
>React : Symbol(React, Decl(errorSpanForUnclosedJsxTag.tsx, 0, 13))
4+
5+
let Foo = {
6+
>Foo : Symbol(Foo, Decl(errorSpanForUnclosedJsxTag.tsx, 2, 3))
7+
8+
Bar() {}
9+
>Bar : Symbol(Bar, Decl(errorSpanForUnclosedJsxTag.tsx, 2, 11))
10+
}
11+
12+
let Baz = () => {}
13+
>Baz : Symbol(Baz, Decl(errorSpanForUnclosedJsxTag.tsx, 6, 3))
14+
15+
let x = < Foo.Bar >Hello
16+
>x : Symbol(x, Decl(errorSpanForUnclosedJsxTag.tsx, 8, 3))
17+
>Foo.Bar : Symbol(Bar, Decl(errorSpanForUnclosedJsxTag.tsx, 2, 11))
18+
>Foo : Symbol(Foo, Decl(errorSpanForUnclosedJsxTag.tsx, 2, 3))
19+
>Bar : Symbol(Bar, Decl(errorSpanForUnclosedJsxTag.tsx, 2, 11))
20+
21+
let y = < Baz >Hello
22+
>Baz : Symbol(Baz, Decl(errorSpanForUnclosedJsxTag.tsx, 6, 3))
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
=== tests/cases/compiler/errorSpanForUnclosedJsxTag.tsx ===
2+
declare const React: any
3+
>React : any
4+
5+
let Foo = {
6+
>Foo : { Bar(): void; }
7+
>{ Bar() {}} : { Bar(): void; }
8+
9+
Bar() {}
10+
>Bar : () => void
11+
}
12+
13+
let Baz = () => {}
14+
>Baz : () => void
15+
>() => {} : () => void
16+
17+
let x = < Foo.Bar >Hello
18+
>x : any
19+
>< Foo.Bar >Hellolet y = < Baz >Hello : any
20+
>Foo.Bar : () => void
21+
>Foo : { Bar(): void; }
22+
>Bar : () => void
23+
24+
let y = < Baz >Hello
25+
>< Baz >Hello : any
26+
>Baz : () => void
27+
> : any
28+
> : any
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @jsx: react
2+
declare const React: any
3+
4+
let Foo = {
5+
Bar() {}
6+
}
7+
8+
let Baz = () => {}
9+
10+
let x = < Foo.Bar >Hello
11+
12+
let y = < Baz >Hello

0 commit comments

Comments
 (0)