diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 631ded027b8..c6bf689518d 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -40728,6 +40728,7 @@ namespace ts {
}
function checkGrammarJsxElement(node: JsxOpeningLikeElement) {
+ checkGrammarJsxName(node.tagName);
checkGrammarTypeArguments(node, node.typeArguments);
const seen = new Map<__String, boolean>();
@@ -40750,6 +40751,29 @@ namespace ts {
}
}
+ function checkGrammarJsxName(node: JsxTagNameExpression) {
+ if (isPropertyAccessExpression(node)) {
+ let propName: JsxTagNameExpression = node;
+ do {
+ const check = checkGrammarJsxNestedIdentifier(propName.name);
+ if (check) {
+ return check;
+ }
+ propName = propName.expression;
+ } while (isPropertyAccessExpression(propName));
+ const check = checkGrammarJsxNestedIdentifier(propName);
+ if (check) {
+ return check;
+ }
+ }
+
+ function checkGrammarJsxNestedIdentifier(name: MemberName | ThisExpression) {
+ if (isIdentifier(name) && idText(name).indexOf(":") !== -1) {
+ return grammarErrorOnNode(name, Diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names);
+ }
+ }
+ }
+
function checkGrammarJsxExpression(node: JsxExpression) {
if (node.expression && isCommaSequence(node.expression)) {
return grammarErrorOnNode(node.expression, Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array);
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 789f7d167d7..ae8fe1998fb 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -2674,6 +2674,10 @@
"category": "Error",
"code": 2632
},
+ "JSX property access expressions cannot include JSX namespace names": {
+ "category": "Error",
+ "code": 2633
+ },
"Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": {
"category": "Error",
diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts
index c42186ea7f6..ca3290b25e1 100644
--- a/src/compiler/scanner.ts
+++ b/src/compiler/scanner.ts
@@ -2335,6 +2335,7 @@ namespace ts {
tokenValue += ":";
pos++;
namespaceSeparator = true;
+ token = SyntaxKind.Identifier; // swap from keyword kind to identifier kind
continue;
}
const oldPos = pos;
diff --git a/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.errors.txt b/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.errors.txt
new file mode 100644
index 00000000000..d758a3ed0c9
--- /dev/null
+++ b/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.errors.txt
@@ -0,0 +1,25 @@
+tests/cases/conformance/jsx/checkJsxNamespaceNamesQuestionableForms.tsx(12,2): error TS2304: Cannot find name 'b:c'.
+tests/cases/conformance/jsx/checkJsxNamespaceNamesQuestionableForms.tsx(12,2): error TS2633: JSX property access expressions cannot include JSX namespace names
+tests/cases/conformance/jsx/checkJsxNamespaceNamesQuestionableForms.tsx(12,10): error TS2304: Cannot find name 'b:c'.
+
+
+==== tests/cases/conformance/jsx/checkJsxNamespaceNamesQuestionableForms.tsx (3 errors) ====
+ declare namespace JSX {
+ interface IntrinsicElements {
+ 'this:b': any;
+ 'b:c': {
+ x: any
+ };
+ 'a:b': any;
+ }
+ }
+
+ ;
+ ;
+ ~~~
+!!! error TS2304: Cannot find name 'b:c'.
+ ~~~
+!!! error TS2633: JSX property access expressions cannot include JSX namespace names
+ ~~~
+!!! error TS2304: Cannot find name 'b:c'.
+ ;
\ No newline at end of file
diff --git a/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.js b/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.js
new file mode 100644
index 00000000000..6189a8f9d78
--- /dev/null
+++ b/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.js
@@ -0,0 +1,19 @@
+//// [checkJsxNamespaceNamesQuestionableForms.tsx]
+declare namespace JSX {
+ interface IntrinsicElements {
+ 'this:b': any;
+ 'b:c': {
+ x: any
+ };
+ 'a:b': any;
+ }
+}
+
+;
+;
+;
+
+//// [checkJsxNamespaceNamesQuestionableForms.jsx]
+;
+;
+;
diff --git a/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.symbols b/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.symbols
new file mode 100644
index 00000000000..405838180ce
--- /dev/null
+++ b/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.symbols
@@ -0,0 +1,31 @@
+=== tests/cases/conformance/jsx/checkJsxNamespaceNamesQuestionableForms.tsx ===
+declare namespace JSX {
+>JSX : Symbol(JSX, Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 0, 0))
+
+ interface IntrinsicElements {
+>IntrinsicElements : Symbol(IntrinsicElements, Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 0, 23))
+
+ 'this:b': any;
+>'this:b' : Symbol(IntrinsicElements['this:b'], Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 1, 33))
+
+ 'b:c': {
+>'b:c' : Symbol(IntrinsicElements['b:c'], Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 2, 22))
+
+ x: any
+>x : Symbol(x, Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 3, 16))
+
+ };
+ 'a:b': any;
+>'a:b' : Symbol(IntrinsicElements['a:b'], Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 5, 10))
+ }
+}
+
+;
+>a:b : Symbol(JSX.IntrinsicElements['a:b'], Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 5, 10))
+>a:b : Symbol(JSX.IntrinsicElements['a:b'], Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 5, 10))
+
+;
+;
+>this:b : Symbol(JSX.IntrinsicElements['this:b'], Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 1, 33))
+>this:b : Symbol(JSX.IntrinsicElements['this:b'], Decl(checkJsxNamespaceNamesQuestionableForms.tsx, 1, 33))
+
diff --git a/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.types b/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.types
new file mode 100644
index 00000000000..9f999220322
--- /dev/null
+++ b/tests/baselines/reference/checkJsxNamespaceNamesQuestionableForms.types
@@ -0,0 +1,37 @@
+=== tests/cases/conformance/jsx/checkJsxNamespaceNamesQuestionableForms.tsx ===
+declare namespace JSX {
+ interface IntrinsicElements {
+ 'this:b': any;
+>'this:b' : any
+
+ 'b:c': {
+>'b:c' : { x: any; }
+
+ x: any
+>x : any
+
+ };
+ 'a:b': any;
+>'a:b' : any
+ }
+}
+
+;
+> : any
+>a:b : any
+>a:b : any
+
+;
+> : any
+>b:c.x : any
+>b:c : any
+>x : any
+>b:c.x : any
+>b:c : any
+>x : any
+
+;
+> : any
+>this:b : any
+>this:b : any
+
diff --git a/tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt b/tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt
index be20bc527a5..ed0df0cdd66 100644
--- a/tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt
+++ b/tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt
@@ -77,6 +77,7 @@ tests/cases/conformance/jsx/6.tsx(1,4): error TS17002: Expected corresponding JS
tests/cases/conformance/jsx/7.tsx(1,13): error TS1002: Unterminated string literal.
tests/cases/conformance/jsx/8.tsx(1,6): error TS17002: Expected corresponding JSX closing tag for 'a:b'.
tests/cases/conformance/jsx/9.tsx(1,2): error TS2304: Cannot find name 'a:b'.
+tests/cases/conformance/jsx/9.tsx(1,2): error TS2633: JSX property access expressions cannot include JSX namespace names
tests/cases/conformance/jsx/9.tsx(1,10): error TS2304: Cannot find name 'a:b'.
@@ -128,10 +129,12 @@ tests/cases/conformance/jsx/9.tsx(1,10): error TS2304: Cannot find name 'a:b'.
;
~~~~
!!! error TS17002: Expected corresponding JSX closing tag for 'a:b'.
-==== tests/cases/conformance/jsx/9.tsx (2 errors) ====
+==== tests/cases/conformance/jsx/9.tsx (3 errors) ====
;
~~~
!!! error TS2304: Cannot find name 'a:b'.
+ ~~~
+!!! error TS2633: JSX property access expressions cannot include JSX namespace names
~~~
!!! error TS2304: Cannot find name 'a:b'.
==== tests/cases/conformance/jsx/10.tsx (6 errors) ====
diff --git a/tests/cases/conformance/jsx/checkJsxNamespaceNamesQuestionableForms.tsx b/tests/cases/conformance/jsx/checkJsxNamespaceNamesQuestionableForms.tsx
new file mode 100644
index 00000000000..e1688610a0c
--- /dev/null
+++ b/tests/cases/conformance/jsx/checkJsxNamespaceNamesQuestionableForms.tsx
@@ -0,0 +1,14 @@
+// @jsx: preserve
+declare namespace JSX {
+ interface IntrinsicElements {
+ 'this:b': any;
+ 'b:c': {
+ x: any
+ };
+ 'a:b': any;
+ }
+}
+
+;
+;
+;
\ No newline at end of file