mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
chore: disallows unicode escape sequence in JSX (#48609)
Co-authored-by: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
This commit is contained in:
co-authored by
Jake Bailey
parent
e78f2a88e1
commit
cd391b066b
@@ -6737,6 +6737,10 @@
|
||||
"category": "Error",
|
||||
"code": 17020
|
||||
},
|
||||
"Unicode escape sequence cannot appear here.": {
|
||||
"category": "Error",
|
||||
"code": 17021
|
||||
},
|
||||
"Circularity detected while resolving configuration: {0}": {
|
||||
"category": "Error",
|
||||
"code": 18000
|
||||
|
||||
+21
-10
@@ -2657,6 +2657,13 @@ namespace Parser {
|
||||
return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage);
|
||||
}
|
||||
|
||||
function parseIdentifierNameErrorOnUnicodeEscapeSequence(): Identifier {
|
||||
if (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape()) {
|
||||
parseErrorAtCurrentToken(Diagnostics.Unicode_escape_sequence_cannot_appear_here);
|
||||
}
|
||||
return createIdentifier(tokenIsIdentifierOrKeyword(token()));
|
||||
}
|
||||
|
||||
function isLiteralPropertyName(): boolean {
|
||||
return tokenIsIdentifierOrKeyword(token()) ||
|
||||
token() === SyntaxKind.StringLiteral ||
|
||||
@@ -3522,7 +3529,7 @@ namespace Parser {
|
||||
entity = finishNode(
|
||||
factory.createQualifiedName(
|
||||
entity,
|
||||
parseRightSideOfDot(allowReservedWords, /*allowPrivateIdentifiers*/ false) as Identifier
|
||||
parseRightSideOfDot(allowReservedWords, /*allowPrivateIdentifiers*/ false, /*allowUnicodeEscapeSequenceInIdentifierName*/ true) as Identifier
|
||||
),
|
||||
pos
|
||||
);
|
||||
@@ -3534,7 +3541,7 @@ namespace Parser {
|
||||
return finishNode(factory.createQualifiedName(entity, name), entity.pos);
|
||||
}
|
||||
|
||||
function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean): Identifier | PrivateIdentifier {
|
||||
function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean, allowUnicodeEscapeSequenceInIdentifierName: boolean): Identifier | PrivateIdentifier {
|
||||
// Technically a keyword is valid here as all identifiers and keywords are identifier names.
|
||||
// However, often we'll encounter this in error situations when the identifier or keyword
|
||||
// is actually starting another valid construct.
|
||||
@@ -3570,7 +3577,11 @@ namespace Parser {
|
||||
return allowPrivateIdentifiers ? node : createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
|
||||
}
|
||||
|
||||
return allowIdentifierNames ? parseIdentifierName() : parseIdentifier();
|
||||
if (allowIdentifierNames) {
|
||||
return allowUnicodeEscapeSequenceInIdentifierName ? parseIdentifierName() : parseIdentifierNameErrorOnUnicodeEscapeSequence();
|
||||
}
|
||||
|
||||
return parseIdentifier();
|
||||
}
|
||||
|
||||
function parseTemplateSpans(isTaggedTemplate: boolean) {
|
||||
@@ -5945,7 +5956,7 @@ namespace Parser {
|
||||
// If it wasn't then just try to parse out a '.' and report an error.
|
||||
parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
|
||||
// private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic
|
||||
return finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true)), pos);
|
||||
return finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true, /*allowUnicodeEscapeSequenceInIdentifierName*/ true)), pos);
|
||||
}
|
||||
|
||||
function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment, mustBeUnary = false): JsxElement | JsxSelfClosingElement | JsxFragment {
|
||||
@@ -6140,7 +6151,7 @@ namespace Parser {
|
||||
}
|
||||
let expression: PropertyAccessExpression | Identifier | ThisExpression = initialExpression;
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
expression = finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false)), pos);
|
||||
expression = finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false, /*allowUnicodeEscapeSequenceInIdentifierName*/ false)), pos);
|
||||
}
|
||||
return expression as JsxTagNameExpression;
|
||||
}
|
||||
@@ -6150,10 +6161,10 @@ namespace Parser {
|
||||
scanJsxIdentifier();
|
||||
|
||||
const isThis = token() === SyntaxKind.ThisKeyword;
|
||||
const tagName = parseIdentifierName();
|
||||
const tagName = parseIdentifierNameErrorOnUnicodeEscapeSequence();
|
||||
if (parseOptional(SyntaxKind.ColonToken)) {
|
||||
scanJsxIdentifier();
|
||||
return finishNode(factory.createJsxNamespacedName(tagName, parseIdentifierName()), pos);
|
||||
return finishNode(factory.createJsxNamespacedName(tagName, parseIdentifierNameErrorOnUnicodeEscapeSequence()), pos);
|
||||
}
|
||||
return isThis ? finishNode(factory.createToken(SyntaxKind.ThisKeyword), pos) : tagName;
|
||||
}
|
||||
@@ -6214,10 +6225,10 @@ namespace Parser {
|
||||
const pos = getNodePos();
|
||||
scanJsxIdentifier();
|
||||
|
||||
const attrName = parseIdentifierName();
|
||||
const attrName = parseIdentifierNameErrorOnUnicodeEscapeSequence();
|
||||
if (parseOptional(SyntaxKind.ColonToken)) {
|
||||
scanJsxIdentifier();
|
||||
return finishNode(factory.createJsxNamespacedName(attrName, parseIdentifierName()), pos);
|
||||
return finishNode(factory.createJsxNamespacedName(attrName, parseIdentifierNameErrorOnUnicodeEscapeSequence()), pos);
|
||||
}
|
||||
return attrName;
|
||||
}
|
||||
@@ -6307,7 +6318,7 @@ namespace Parser {
|
||||
}
|
||||
|
||||
function parsePropertyAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
|
||||
const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true);
|
||||
const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true, /*allowUnicodeEscapeSequenceInIdentifierName*/ true);
|
||||
const isOptionalChain = questionDotToken || tryReparseOptionalChain(expression);
|
||||
const propertyAccess = isOptionalChain ?
|
||||
factoryCreatePropertyAccessChain(expression, questionDotToken, name) :
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
file.tsx(15,4): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(16,4): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(17,4): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(18,4): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(19,6): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(20,4): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(21,4): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(22,4): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(23,4): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(26,9): error TS17021: Unicode escape sequence cannot appear here.
|
||||
file.tsx(27,9): error TS17021: Unicode escape sequence cannot appear here.
|
||||
|
||||
|
||||
==== file.tsx (11 errors) ====
|
||||
import * as React from "react";
|
||||
declare global {
|
||||
namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
"a-b": any;
|
||||
"a-c": any;
|
||||
}
|
||||
}
|
||||
}
|
||||
const Compa = (x: {x: number}) => <div>{"" + x}</div>;
|
||||
const x = { video: () => null }
|
||||
|
||||
// unicode escape sequence is not allowed in tag name or JSX attribute name.
|
||||
// tag name:
|
||||
; <\u0061></a>
|
||||
~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
; <\u0061-b></a-b>
|
||||
~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
; <a-\u0063></a-c>
|
||||
~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
; <Comp\u0061 x={12} />
|
||||
~~~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
; <x.\u0076ideo />
|
||||
~~~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
; <\u{0061}></a>
|
||||
~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
; <\u{0061}-b></a-b>
|
||||
~~~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
; <a-\u{0063}></a-c>
|
||||
~~~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
; <Comp\u{0061} x={12} />
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
|
||||
// attribute name
|
||||
;<video data-\u0076ideo />
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
;<video \u0073rc="" />
|
||||
~~~~~~~~
|
||||
!!! error TS17021: Unicode escape sequence cannot appear here.
|
||||
|
||||
@@ -11,26 +11,37 @@ declare global {
|
||||
}
|
||||
}
|
||||
const Compa = (x: {x: number}) => <div>{"" + x}</div>;
|
||||
const x = { video: () => null }
|
||||
|
||||
let a = <\u0061></a>; // works
|
||||
let ab = <\u0061-b></a-b>; // works
|
||||
let ac = <a-\u0063></a-c>; // works
|
||||
let compa = <Comp\u0061 x={12} />; // works
|
||||
// unicode escape sequence is not allowed in tag name or JSX attribute name.
|
||||
// tag name:
|
||||
; <\u0061></a>
|
||||
; <\u0061-b></a-b>
|
||||
; <a-\u0063></a-c>
|
||||
; <Comp\u0061 x={12} />
|
||||
; <x.\u0076ideo />
|
||||
; <\u{0061}></a>
|
||||
; <\u{0061}-b></a-b>
|
||||
; <a-\u{0063}></a-c>
|
||||
; <Comp\u{0061} x={12} />
|
||||
|
||||
let a2 = <\u{0061}></a>; // works
|
||||
let ab2 = <\u{0061}-b></a-b>; // works
|
||||
let ac2 = <a-\u{0063}></a-c>; // works
|
||||
let compa2 = <Comp\u{0061} x={12} />; // works
|
||||
// attribute name
|
||||
;<video data-\u0076ideo />
|
||||
;<video \u0073rc="" />
|
||||
|
||||
|
||||
//// [file.js]
|
||||
import * as React from "react";
|
||||
const Compa = (x) => React.createElement("div", null, "" + x);
|
||||
let a = React.createElement("a", null); // works
|
||||
let ab = React.createElement("a-b", null); // works
|
||||
let ac = React.createElement("a-c", null); // works
|
||||
let compa = React.createElement(Comp\u0061, { x: 12 }); // works
|
||||
let a2 = React.createElement("a", null); // works
|
||||
let ab2 = React.createElement("a-b", null); // works
|
||||
let ac2 = React.createElement("a-c", null); // works
|
||||
let compa2 = React.createElement(Comp\u{0061}, { x: 12 }); // works
|
||||
const x = { video: () => null };
|
||||
React.createElement("a", null);
|
||||
React.createElement("a-b", null);
|
||||
React.createElement("a-c", null);
|
||||
React.createElement(Comp\u0061, { x: 12 });
|
||||
React.createElement(x.\u0076ideo, null);
|
||||
React.createElement("a", null);
|
||||
React.createElement("a-b", null);
|
||||
React.createElement("a-c", null);
|
||||
React.createElement(Comp\u{0061}, { x: 12 });
|
||||
React.createElement("video", { "data-video": true });
|
||||
React.createElement("video", { \u0073rc: "" });
|
||||
|
||||
@@ -29,43 +29,55 @@ const Compa = (x: {x: number}) => <div>{"" + x}</div>;
|
||||
>x : Symbol(x, Decl(file.tsx, 9, 15))
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
|
||||
|
||||
let a = <\u0061></a>; // works
|
||||
>a : Symbol(a, Decl(file.tsx, 11, 3))
|
||||
const x = { video: () => null }
|
||||
>x : Symbol(x, Decl(file.tsx, 10, 5))
|
||||
>video : Symbol(video, Decl(file.tsx, 10, 11))
|
||||
|
||||
// unicode escape sequence is not allowed in tag name or JSX attribute name.
|
||||
// tag name:
|
||||
; <\u0061></a>
|
||||
>\u0061 : Symbol(JSX.IntrinsicElements.a, Decl(react.d.ts, 2370, 33))
|
||||
>a : Symbol(JSX.IntrinsicElements.a, Decl(react.d.ts, 2370, 33))
|
||||
|
||||
let ab = <\u0061-b></a-b>; // works
|
||||
>ab : Symbol(ab, Decl(file.tsx, 12, 3))
|
||||
; <\u0061-b></a-b>
|
||||
>\u0061-b : Symbol(JSX.IntrinsicElements["a-b"], Decl(file.tsx, 3, 37))
|
||||
>a-b : Symbol(JSX.IntrinsicElements["a-b"], Decl(file.tsx, 3, 37))
|
||||
|
||||
let ac = <a-\u0063></a-c>; // works
|
||||
>ac : Symbol(ac, Decl(file.tsx, 13, 3))
|
||||
; <a-\u0063></a-c>
|
||||
>a-\u0063 : Symbol(JSX.IntrinsicElements["a-c"], Decl(file.tsx, 4, 23))
|
||||
>a-c : Symbol(JSX.IntrinsicElements["a-c"], Decl(file.tsx, 4, 23))
|
||||
|
||||
let compa = <Comp\u0061 x={12} />; // works
|
||||
>compa : Symbol(compa, Decl(file.tsx, 14, 3))
|
||||
; <Comp\u0061 x={12} />
|
||||
>Comp\u0061 : Symbol(Compa, Decl(file.tsx, 9, 5))
|
||||
>x : Symbol(x, Decl(file.tsx, 14, 23))
|
||||
>x : Symbol(x, Decl(file.tsx, 17, 13))
|
||||
|
||||
let a2 = <\u{0061}></a>; // works
|
||||
>a2 : Symbol(a2, Decl(file.tsx, 16, 3))
|
||||
; <x.\u0076ideo />
|
||||
>x.\u0076ideo : Symbol(video, Decl(file.tsx, 10, 11))
|
||||
>x : Symbol(x, Decl(file.tsx, 10, 5))
|
||||
>\u0076ideo : Symbol(video, Decl(file.tsx, 10, 11))
|
||||
|
||||
; <\u{0061}></a>
|
||||
>\u{0061} : Symbol(JSX.IntrinsicElements.a, Decl(react.d.ts, 2370, 33))
|
||||
>a : Symbol(JSX.IntrinsicElements.a, Decl(react.d.ts, 2370, 33))
|
||||
|
||||
let ab2 = <\u{0061}-b></a-b>; // works
|
||||
>ab2 : Symbol(ab2, Decl(file.tsx, 17, 3))
|
||||
; <\u{0061}-b></a-b>
|
||||
>\u{0061}-b : Symbol(JSX.IntrinsicElements["a-b"], Decl(file.tsx, 3, 37))
|
||||
>a-b : Symbol(JSX.IntrinsicElements["a-b"], Decl(file.tsx, 3, 37))
|
||||
|
||||
let ac2 = <a-\u{0063}></a-c>; // works
|
||||
>ac2 : Symbol(ac2, Decl(file.tsx, 18, 3))
|
||||
; <a-\u{0063}></a-c>
|
||||
>a-\u{0063} : Symbol(JSX.IntrinsicElements["a-c"], Decl(file.tsx, 4, 23))
|
||||
>a-c : Symbol(JSX.IntrinsicElements["a-c"], Decl(file.tsx, 4, 23))
|
||||
|
||||
let compa2 = <Comp\u{0061} x={12} />; // works
|
||||
>compa2 : Symbol(compa2, Decl(file.tsx, 19, 3))
|
||||
; <Comp\u{0061} x={12} />
|
||||
>Comp\u{0061} : Symbol(Compa, Decl(file.tsx, 9, 5))
|
||||
>x : Symbol(x, Decl(file.tsx, 19, 26))
|
||||
>x : Symbol(x, Decl(file.tsx, 22, 15))
|
||||
|
||||
// attribute name
|
||||
;<video data-\u0076ideo />
|
||||
>video : Symbol(JSX.IntrinsicElements.video, Decl(react.d.ts, 2481, 44))
|
||||
>data-\u0076ideo : Symbol(data-\u0076ideo, Decl(file.tsx, 25, 7))
|
||||
|
||||
;<video \u0073rc="" />
|
||||
>video : Symbol(JSX.IntrinsicElements.video, Decl(react.d.ts, 2481, 44))
|
||||
>\u0073rc : Symbol(\u0073rc, Decl(file.tsx, 26, 7))
|
||||
|
||||
|
||||
@@ -29,53 +29,70 @@ const Compa = (x: {x: number}) => <div>{"" + x}</div>;
|
||||
>x : { x: number; }
|
||||
>div : any
|
||||
|
||||
let a = <\u0061></a>; // works
|
||||
>a : JSX.Element
|
||||
><\u0061></a> : JSX.Element
|
||||
>\u0061 : JSX.Element
|
||||
>a : JSX.Element
|
||||
const x = { video: () => null }
|
||||
>x : { video: () => any; }
|
||||
>{ video: () => null } : { video: () => any; }
|
||||
>video : () => any
|
||||
>() => null : () => any
|
||||
|
||||
let ab = <\u0061-b></a-b>; // works
|
||||
>ab : JSX.Element
|
||||
// unicode escape sequence is not allowed in tag name or JSX attribute name.
|
||||
// tag name:
|
||||
; <\u0061></a>
|
||||
><\u0061></a> : JSX.Element
|
||||
>\u0061 : any
|
||||
>a : any
|
||||
|
||||
; <\u0061-b></a-b>
|
||||
><\u0061-b></a-b> : JSX.Element
|
||||
>\u0061-b : any
|
||||
>a-b : any
|
||||
|
||||
let ac = <a-\u0063></a-c>; // works
|
||||
>ac : JSX.Element
|
||||
; <a-\u0063></a-c>
|
||||
><a-\u0063></a-c> : JSX.Element
|
||||
>a-\u0063 : any
|
||||
>a-c : any
|
||||
|
||||
let compa = <Comp\u0061 x={12} />; // works
|
||||
>compa : JSX.Element
|
||||
; <Comp\u0061 x={12} />
|
||||
><Comp\u0061 x={12} /> : JSX.Element
|
||||
>Comp\u0061 : (x: { x: number; }) => JSX.Element
|
||||
>x : number
|
||||
>12 : 12
|
||||
|
||||
let a2 = <\u{0061}></a>; // works
|
||||
>a2 : JSX.Element
|
||||
><\u{0061}></a> : JSX.Element
|
||||
>\u{0061} : JSX.Element
|
||||
>a : JSX.Element
|
||||
; <x.\u0076ideo />
|
||||
><x.\u0076ideo /> : JSX.Element
|
||||
>x.\u0076ideo : () => any
|
||||
>x : { video: () => any; }
|
||||
>\u0076ideo : () => any
|
||||
|
||||
let ab2 = <\u{0061}-b></a-b>; // works
|
||||
>ab2 : JSX.Element
|
||||
; <\u{0061}></a>
|
||||
><\u{0061}></a> : JSX.Element
|
||||
>\u{0061} : any
|
||||
>a : any
|
||||
|
||||
; <\u{0061}-b></a-b>
|
||||
><\u{0061}-b></a-b> : JSX.Element
|
||||
>\u{0061}-b : any
|
||||
>a-b : any
|
||||
|
||||
let ac2 = <a-\u{0063}></a-c>; // works
|
||||
>ac2 : JSX.Element
|
||||
; <a-\u{0063}></a-c>
|
||||
><a-\u{0063}></a-c> : JSX.Element
|
||||
>a-\u{0063} : any
|
||||
>a-c : any
|
||||
|
||||
let compa2 = <Comp\u{0061} x={12} />; // works
|
||||
>compa2 : JSX.Element
|
||||
; <Comp\u{0061} x={12} />
|
||||
><Comp\u{0061} x={12} /> : JSX.Element
|
||||
>Comp\u{0061} : (x: { x: number; }) => JSX.Element
|
||||
>x : number
|
||||
>12 : 12
|
||||
|
||||
// attribute name
|
||||
;<video data-\u0076ideo />
|
||||
><video data-\u0076ideo /> : JSX.Element
|
||||
>video : any
|
||||
>data-\u0076ideo : true
|
||||
|
||||
;<video \u0073rc="" />
|
||||
><video \u0073rc="" /> : JSX.Element
|
||||
>video : any
|
||||
>\u0073rc : string
|
||||
|
||||
|
||||
@@ -15,13 +15,20 @@ declare global {
|
||||
}
|
||||
}
|
||||
const Compa = (x: {x: number}) => <div>{"" + x}</div>;
|
||||
const x = { video: () => null }
|
||||
|
||||
let a = <\u0061></a>; // works
|
||||
let ab = <\u0061-b></a-b>; // works
|
||||
let ac = <a-\u0063></a-c>; // works
|
||||
let compa = <Comp\u0061 x={12} />; // works
|
||||
// unicode escape sequence is not allowed in tag name or JSX attribute name.
|
||||
// tag name:
|
||||
; <\u0061></a>
|
||||
; <\u0061-b></a-b>
|
||||
; <a-\u0063></a-c>
|
||||
; <Comp\u0061 x={12} />
|
||||
; <x.\u0076ideo />
|
||||
; <\u{0061}></a>
|
||||
; <\u{0061}-b></a-b>
|
||||
; <a-\u{0063}></a-c>
|
||||
; <Comp\u{0061} x={12} />
|
||||
|
||||
let a2 = <\u{0061}></a>; // works
|
||||
let ab2 = <\u{0061}-b></a-b>; // works
|
||||
let ac2 = <a-\u{0063}></a-c>; // works
|
||||
let compa2 = <Comp\u{0061} x={12} />; // works
|
||||
// attribute name
|
||||
;<video data-\u0076ideo />
|
||||
;<video \u0073rc="" />
|
||||
|
||||
Reference in New Issue
Block a user