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