Skip to content

Commit 3f809c8

Browse files
committed
Support xml namespace prefix for JSX elements and attributes
Just as with the `-` character, `:` is now also treated specially in JSX element and attribute names, but is only allowed a single time, and not at the beginning or end of the name, as is specified in the JSX spec. All tests in jsxInvalidEsprimaTestSuite still fail, but for slightly different reasons now. Two lines in jsxEsprimaFbTestSuite were uncommented as they included elements with namespaces, and they now pass without error.
1 parent 2458c8a commit 3f809c8

15 files changed

+439
-77
lines changed

src/compiler/scanner.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2231,22 +2231,35 @@ namespace ts {
22312231
// they allow dashes
22322232
function scanJsxIdentifier(): SyntaxKind {
22332233
if (tokenIsIdentifierOrKeyword(token)) {
2234-
// An identifier or keyword has already been parsed - check for a `-` and then append it and everything after it to the token
2234+
// An identifier or keyword has already been parsed - check for a `-` or a single instance of `:` and then append it and
2235+
// everything after it to the token
22352236
// Do note that this means that `scanJsxIdentifier` effectively _mutates_ the visible token without advancing to a new token
22362237
// Any caller should be expecting this behavior and should only read the pos or token value after calling it.
2238+
let namespaceSeparator = false;
22372239
while (pos < end) {
22382240
const ch = text.charCodeAt(pos);
22392241
if (ch === CharacterCodes.minus) {
22402242
tokenValue += "-";
22412243
pos++;
22422244
continue;
22432245
}
2246+
else if (ch === CharacterCodes.colon && !namespaceSeparator) {
2247+
tokenValue += ":";
2248+
pos++;
2249+
namespaceSeparator = true;
2250+
continue;
2251+
}
22442252
const oldPos = pos;
22452253
tokenValue += scanIdentifierParts(); // reuse `scanIdentifierParts` so unicode escapes are handled
22462254
if (pos === oldPos) {
22472255
break;
22482256
}
22492257
}
2258+
// Do not include a trailing namespace separator in the token, since this is against the spec.
2259+
if (tokenValue.slice(-1) === ":") {
2260+
tokenValue = tokenValue.slice(0, -1);
2261+
pos--;
2262+
}
22502263
}
22512264
return token;
22522265
}

tests/baselines/reference/jsxEsprimaFbTestSuite.errors.txt

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,1): error TS2695: Left side of comma operator is unused and has no side effects.
2-
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,17): error TS1005: '{' expected.
3-
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,23): error TS2304: Cannot find name 'right'.
4-
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,23): error TS2657: JSX expressions must have one parent element.
5-
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,41): error TS1382: Unexpected token. Did you mean `{'>'}` or `&gt;`?
6-
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,57): error TS1109: Expression expected.
7-
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,58): error TS1109: Expression expected.
1+
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(40,1): error TS2695: Left side of comma operator is unused and has no side effects.
2+
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(40,17): error TS1005: '{' expected.
3+
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(40,23): error TS2304: Cannot find name 'right'.
4+
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(40,23): error TS2657: JSX expressions must have one parent element.
5+
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(40,41): error TS1382: Unexpected token. Did you mean `{'>'}` or `&gt;`?
6+
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(40,57): error TS1109: Expression expected.
7+
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(40,58): error TS1109: Expression expected.
88

99

1010
==== tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx (7 errors) ====
@@ -15,12 +15,13 @@ tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,58): error TS1109: Expr
1515
declare var x;
1616
declare var a;
1717
declare var props;
18+
declare var value;
1819

1920
<a />;
2021

21-
//<n:a n:v />; Namespace unsuported
22+
<n:a n:v />;
2223

23-
//<a n:foo="bar"> {value} <b><c /></b></a>; Namespace unsuported
24+
<a n:foo="bar"> {value} <b><c /></b></a>;
2425

2526
<a b={" "} c=" " d="&amp;" e="id=1&group=2" f="&#123456789" g="&#123*;" h="&#x;" />;
2627

tests/baselines/reference/jsxEsprimaFbTestSuite.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ declare var LeftRight;
66
declare var x;
77
declare var a;
88
declare var props;
9+
declare var value;
910

1011
<a />;
1112

12-
//<n:a n:v />; Namespace unsuported
13+
<n:a n:v />;
1314

14-
//<a n:foo="bar"> {value} <b><c /></b></a>; Namespace unsuported
15+
<a n:foo="bar"> {value} <b><c /></b></a>;
1516

1617
<a b={" "} c=" " d="&amp;" e="id=1&group=2" f="&#123456789" g="&#123*;" h="&#x;" />;
1718

@@ -56,8 +57,8 @@ baz
5657

5758
//// [jsxEsprimaFbTestSuite.jsx]
5859
<a />;
59-
//<n:a n:v />; Namespace unsuported
60-
//<a n:foo="bar"> {value} <b><c /></b></a>; Namespace unsuported
60+
<n:a n:v/>;
61+
<a n:foo="bar"> {value} <b><c /></b></a>;
6162
<a b={" "} c=" " d="&amp;" e="id=1&group=2" f="&#123456789" g="&#123*;" h="&#x;"/>;
6263
<a b="&notanentity;"/>;
6364
<a />;

tests/baselines/reference/jsxEsprimaFbTestSuite.symbols

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,29 @@ declare var a;
2020
declare var props;
2121
>props : Symbol(props, Decl(jsxEsprimaFbTestSuite.tsx, 6, 11))
2222

23+
declare var value;
24+
>value : Symbol(value, Decl(jsxEsprimaFbTestSuite.tsx, 7, 11))
25+
2326
<a />;
2427

25-
//<n:a n:v />; Namespace unsuported
28+
<n:a n:v />;
29+
>n:v : Symbol(n:v, Decl(jsxEsprimaFbTestSuite.tsx, 11, 4))
2630

27-
//<a n:foo="bar"> {value} <b><c /></b></a>; Namespace unsuported
31+
<a n:foo="bar"> {value} <b><c /></b></a>;
32+
>n:foo : Symbol(n:foo, Decl(jsxEsprimaFbTestSuite.tsx, 13, 2))
33+
>value : Symbol(value, Decl(jsxEsprimaFbTestSuite.tsx, 7, 11))
2834

2935
<a b={" "} c=" " d="&amp;" e="id=1&group=2" f="&#123456789" g="&#123*;" h="&#x;" />;
30-
>b : Symbol(b, Decl(jsxEsprimaFbTestSuite.tsx, 14, 2))
31-
>c : Symbol(c, Decl(jsxEsprimaFbTestSuite.tsx, 14, 10))
32-
>d : Symbol(d, Decl(jsxEsprimaFbTestSuite.tsx, 14, 16))
33-
>e : Symbol(e, Decl(jsxEsprimaFbTestSuite.tsx, 14, 26))
34-
>f : Symbol(f, Decl(jsxEsprimaFbTestSuite.tsx, 14, 43))
35-
>g : Symbol(g, Decl(jsxEsprimaFbTestSuite.tsx, 14, 59))
36-
>h : Symbol(h, Decl(jsxEsprimaFbTestSuite.tsx, 14, 71))
36+
>b : Symbol(b, Decl(jsxEsprimaFbTestSuite.tsx, 15, 2))
37+
>c : Symbol(c, Decl(jsxEsprimaFbTestSuite.tsx, 15, 10))
38+
>d : Symbol(d, Decl(jsxEsprimaFbTestSuite.tsx, 15, 16))
39+
>e : Symbol(e, Decl(jsxEsprimaFbTestSuite.tsx, 15, 26))
40+
>f : Symbol(f, Decl(jsxEsprimaFbTestSuite.tsx, 15, 43))
41+
>g : Symbol(g, Decl(jsxEsprimaFbTestSuite.tsx, 15, 59))
42+
>h : Symbol(h, Decl(jsxEsprimaFbTestSuite.tsx, 15, 71))
3743

3844
<a b="&notanentity;" />;
39-
>b : Symbol(b, Decl(jsxEsprimaFbTestSuite.tsx, 16, 2))
45+
>b : Symbol(b, Decl(jsxEsprimaFbTestSuite.tsx, 17, 2))
4046

4147
<a
4248
/>;
@@ -49,15 +55,15 @@ declare var props;
4955
>AbC_def : Symbol(AbC_def, Decl(jsxEsprimaFbTestSuite.tsx, 2, 11))
5056

5157
test="&#x0026;&#38;">
52-
>test : Symbol(test, Decl(jsxEsprimaFbTestSuite.tsx, 22, 8))
58+
>test : Symbol(test, Decl(jsxEsprimaFbTestSuite.tsx, 23, 8))
5359

5460
bar
5561
baz
5662
</AbC_def>;
5763
>AbC_def : Symbol(AbC_def, Decl(jsxEsprimaFbTestSuite.tsx, 2, 11))
5864

5965
<a b={x ? <c /> : <d />} />;
60-
>b : Symbol(b, Decl(jsxEsprimaFbTestSuite.tsx, 28, 2))
66+
>b : Symbol(b, Decl(jsxEsprimaFbTestSuite.tsx, 29, 2))
6167
>x : Symbol(x, Decl(jsxEsprimaFbTestSuite.tsx, 4, 11))
6268

6369
<a>{}</a>;
@@ -70,7 +76,7 @@ baz
7076

7177
<LeftRight left=<a /> right=<b>monkeys /> gorillas</b> />;
7278
>LeftRight : Symbol(LeftRight, Decl(jsxEsprimaFbTestSuite.tsx, 3, 11))
73-
>left : Symbol(left, Decl(jsxEsprimaFbTestSuite.tsx, 38, 10))
79+
>left : Symbol(left, Decl(jsxEsprimaFbTestSuite.tsx, 39, 10))
7480

7581
<a.b></a.b>;
7682
>a : Symbol(a, Decl(jsxEsprimaFbTestSuite.tsx, 5, 11))
@@ -88,11 +94,11 @@ baz
8894

8995
<div {...props} post="attribute" />;
9096
>props : Symbol(props, Decl(jsxEsprimaFbTestSuite.tsx, 6, 11))
91-
>post : Symbol(post, Decl(jsxEsprimaFbTestSuite.tsx, 48, 15))
97+
>post : Symbol(post, Decl(jsxEsprimaFbTestSuite.tsx, 49, 15))
9298

9399
<div pre="leading" pre2="attribute" {...props}></div>;
94-
>pre : Symbol(pre, Decl(jsxEsprimaFbTestSuite.tsx, 50, 4))
95-
>pre2 : Symbol(pre2, Decl(jsxEsprimaFbTestSuite.tsx, 50, 18))
100+
>pre : Symbol(pre, Decl(jsxEsprimaFbTestSuite.tsx, 51, 4))
101+
>pre2 : Symbol(pre2, Decl(jsxEsprimaFbTestSuite.tsx, 51, 18))
96102
>props : Symbol(props, Decl(jsxEsprimaFbTestSuite.tsx, 6, 11))
97103

98104
<a> </a>;

tests/baselines/reference/jsxEsprimaFbTestSuite.types

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,29 @@ declare var a;
2020
declare var props;
2121
>props : any
2222

23+
declare var value;
24+
>value : any
25+
2326
<a />;
2427
><a /> : any
2528
>a : any
2629

27-
//<n:a n:v />; Namespace unsuported
30+
<n:a n:v />;
31+
><n:a n:v /> : any
32+
>n:a : any
33+
>n:v : true
2834

29-
//<a n:foo="bar"> {value} <b><c /></b></a>; Namespace unsuported
35+
<a n:foo="bar"> {value} <b><c /></b></a>;
36+
><a n:foo="bar"> {value} <b><c /></b></a> : any
37+
>a : any
38+
>n:foo : string
39+
>value : any
40+
><b><c /></b> : any
41+
>b : any
42+
><c /> : any
43+
>c : any
44+
>b : any
45+
>a : any
3046

3147
<a b={" "} c=" " d="&amp;" e="id=1&group=2" f="&#123456789" g="&#123*;" h="&#x;" />;
3248
><a b={" "} c=" " d="&amp;" e="id=1&group=2" f="&#123456789" g="&#123*;" h="&#x;" /> : any

tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,9 @@ tests/cases/conformance/jsx/5.tsx(1,2): error TS17008: JSX element 'a' has no co
7777
tests/cases/conformance/jsx/5.tsx(1,5): error TS1005: '</' expected.
7878
tests/cases/conformance/jsx/6.tsx(1,4): error TS17002: Expected corresponding JSX closing tag for 'a'.
7979
tests/cases/conformance/jsx/7.tsx(1,13): error TS1002: Unterminated string literal.
80-
tests/cases/conformance/jsx/8.tsx(1,3): error TS1003: Identifier expected.
81-
tests/cases/conformance/jsx/8.tsx(1,6): error TS17002: Expected corresponding JSX closing tag for 'a'.
82-
tests/cases/conformance/jsx/9.tsx(1,3): error TS1003: Identifier expected.
83-
tests/cases/conformance/jsx/9.tsx(1,5): error TS1003: Identifier expected.
84-
tests/cases/conformance/jsx/9.tsx(1,11): error TS1005: '>' expected.
85-
tests/cases/conformance/jsx/9.tsx(1,12): error TS2304: Cannot find name 'b'.
86-
tests/cases/conformance/jsx/9.tsx(1,16): error TS1109: Expression expected.
80+
tests/cases/conformance/jsx/8.tsx(1,6): error TS17002: Expected corresponding JSX closing tag for 'a:b'.
81+
tests/cases/conformance/jsx/9.tsx(1,2): error TS2304: Cannot find name 'a:b'.
82+
tests/cases/conformance/jsx/9.tsx(1,10): error TS2304: Cannot find name 'a:b'.
8783

8884

8985
==== tests/cases/conformance/jsx/1.tsx (3 errors) ====
@@ -130,24 +126,16 @@ tests/cases/conformance/jsx/9.tsx(1,16): error TS1109: Expression expected.
130126
<a foo="bar;
131127

132128
!!! error TS1002: Unterminated string literal.
133-
==== tests/cases/conformance/jsx/8.tsx (2 errors) ====
129+
==== tests/cases/conformance/jsx/8.tsx (1 errors) ====
134130
<a:b></b>;
135-
~
136-
!!! error TS1003: Identifier expected.
137131
~~~~
138-
!!! error TS17002: Expected corresponding JSX closing tag for 'a'.
139-
==== tests/cases/conformance/jsx/9.tsx (5 errors) ====
132+
!!! error TS17002: Expected corresponding JSX closing tag for 'a:b'.
133+
==== tests/cases/conformance/jsx/9.tsx (2 errors) ====
140134
<a:b.c></a:b.c>;
141-
~
142-
!!! error TS1003: Identifier expected.
143-
~
144-
!!! error TS1003: Identifier expected.
145-
~
146-
!!! error TS1005: '>' expected.
147-
~
148-
!!! error TS2304: Cannot find name 'b'.
149-
~
150-
!!! error TS1109: Expression expected.
135+
~~~
136+
!!! error TS2304: Cannot find name 'a:b'.
137+
~~~
138+
!!! error TS2304: Cannot find name 'a:b'.
151139
==== tests/cases/conformance/jsx/10.tsx (6 errors) ====
152140
<a.b:c></a.b:c>;
153141
~

tests/baselines/reference/jsxInvalidEsprimaTestSuite.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,9 @@ a / > ;
9090
//// [7.jsx]
9191
<a foo="bar;/>;
9292
//// [8.jsx]
93-
<a b></b>;
93+
<a:b></b>;
9494
//// [9.jsx]
95-
<a b c></a>;
96-
b.c > ;
95+
<a:b.c></a:b.c>;
9796
//// [10.jsx]
9897
<a.b c></a.b>;
9998
c > ;

tests/baselines/reference/jsxInvalidEsprimaTestSuite.symbols

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,9 @@ No type information for this code.=== tests/cases/conformance/jsx/7.tsx ===
2222

2323
=== tests/cases/conformance/jsx/8.tsx ===
2424
<a:b></b>;
25-
>b : Symbol(b, Decl(8.tsx, 0, 3))
26-
27-
=== tests/cases/conformance/jsx/9.tsx ===
25+
No type information for this code.=== tests/cases/conformance/jsx/9.tsx ===
2826
<a:b.c></a:b.c>;
29-
>b : Symbol(b, Decl(9.tsx, 0, 3))
30-
>c : Symbol(c, Decl(9.tsx, 0, 5))
31-
32-
=== tests/cases/conformance/jsx/10.tsx ===
27+
No type information for this code.=== tests/cases/conformance/jsx/10.tsx ===
3328
<a.b:c></a.b:c>;
3429
>c : Symbol(c, Decl(10.tsx, 0, 5))
3530

tests/baselines/reference/jsxInvalidEsprimaTestSuite.types

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,18 @@ declare var React: any;
5151
=== tests/cases/conformance/jsx/8.tsx ===
5252
<a:b></b>;
5353
><a:b></b> : any
54-
>a : any
55-
>b : true
54+
>a:b : any
5655
>b : any
5756

5857
=== tests/cases/conformance/jsx/9.tsx ===
5958
<a:b.c></a:b.c>;
60-
><a:b.c></a : any
61-
>a : any
62-
>b : true
63-
>c : true
64-
>a : any
65-
>b.c> : boolean
66-
>b.c : any
67-
>b : any
59+
><a:b.c></a:b.c> : any
60+
>a:b.c : any
61+
>a:b : any
62+
>c : any
63+
>a:b.c : any
64+
>a:b : any
6865
>c : any
69-
> : any
7066

7167
=== tests/cases/conformance/jsx/10.tsx ===
7268
<a.b:c></a.b:c>;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(7,32): error TS1003: Identifier expected.
2+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(8,32): error TS1003: Identifier expected.
3+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(8,45): error TS1005: '>' expected.
4+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(8,50): error TS1005: ',' expected.
5+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(8,51): error TS1109: Expression expected.
6+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(9,32): error TS1003: Identifier expected.
7+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(9,60): error TS1005: '>' expected.
8+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(9,65): error TS1005: ',' expected.
9+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(9,66): error TS1109: Expression expected.
10+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(10,32): error TS1003: Identifier expected.
11+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(10,53): error TS1005: '>' expected.
12+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(10,58): error TS1005: ',' expected.
13+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(10,59): error TS1109: Expression expected.
14+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(11,32): error TS1003: Identifier expected.
15+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(11,68): error TS1005: '>' expected.
16+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(11,73): error TS1005: ',' expected.
17+
tests/cases/compiler/jsxNamespacePrefixInName.tsx(11,74): error TS1109: Expression expected.
18+
19+
20+
==== tests/cases/compiler/jsxNamespacePrefixInName.tsx (17 errors) ====
21+
var justElement1 = <a:element />;
22+
var justElement2 = <a:element></a:element>;
23+
var justElement3 = <a:element attr={"value"}></a:element>;
24+
var justElement4 = <a:element>{"text"}</a:element>;
25+
var justElement5 = <a:element attr={"value"}>{"text"}</a:element>;
26+
27+
var tooManySeparators1 = <a:ele:ment />;
28+
~
29+
!!! error TS1003: Identifier expected.
30+
var tooManySeparators2 = <a:ele:ment></a:ele:ment>;
31+
~
32+
!!! error TS1003: Identifier expected.
33+
~
34+
!!! error TS1005: '>' expected.
35+
~
36+
!!! error TS1005: ',' expected.
37+
~
38+
!!! error TS1109: Expression expected.
39+
var tooManySeparators3 = <a:ele:ment attr={"value"}></a:ele:ment>;
40+
~
41+
!!! error TS1003: Identifier expected.
42+
~
43+
!!! error TS1005: '>' expected.
44+
~
45+
!!! error TS1005: ',' expected.
46+
~
47+
!!! error TS1109: Expression expected.
48+
var tooManySeparators4 = <a:ele:ment>{"text"}</a:ele:ment>;
49+
~
50+
!!! error TS1003: Identifier expected.
51+
~
52+
!!! error TS1005: '>' expected.
53+
~
54+
!!! error TS1005: ',' expected.
55+
~
56+
!!! error TS1109: Expression expected.
57+
var tooManySeparators5 = <a:ele:ment attr={"value"}>{"text"}</a:ele:ment>;
58+
~
59+
!!! error TS1003: Identifier expected.
60+
~
61+
!!! error TS1005: '>' expected.
62+
~
63+
!!! error TS1005: ',' expected.
64+
~
65+
!!! error TS1109: Expression expected.
66+
67+
var justAttribute1 = <element a:attr={"value"} />;
68+
var justAttribute2 = <element a:attr={"value"}></element>;
69+
var justAttribute3 = <element a:attr={"value"}>{"text"}</element>;
70+
71+
var both1 = <a:element a:attr={"value"} />;
72+
var both2 = <a:element k:attr={"value"}></a:element>;
73+
var both3 = <a:element a:attr={"value"}>{"text"}</a:element>;
74+

0 commit comments

Comments
 (0)