From f86a730371c506d5ca9864b8d3a4b1835e1d4d47 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Tue, 11 Apr 2017 10:52:18 -0700 Subject: [PATCH] Consider whitespace that won't be emitted to be different kind so that we won't include in typ-checking --- src/compiler/checker.ts | 15 ++++++--------- src/compiler/parser.ts | 8 ++++++-- src/compiler/scanner.ts | 21 ++++++++++++++++++++- src/compiler/types.ts | 1 + 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ff10bea4f97..2c9d4f95d5f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13275,7 +13275,7 @@ namespace ts { const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ? openingLikeElement.parent as JsxElement : undefined; let containsSynthesizedJsxChildren = false; - // Comment + // We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement if (parent && parent.openingElement === openingLikeElement && parent.children.length > 0) { // Error if there is a attribute named "children" and children element. // This is because children element will overwrite the value from attributes @@ -13287,7 +13287,11 @@ namespace ts { const childrenPropSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, jsxChildrenPropertyName); const childrenTypes: Type[] = []; for (const child of (parent as JsxElement).children) { - childrenTypes.push(child.kind === SyntaxKind.JsxText ? stringType : checkExpression(child)); + // In React, JSX text that contains only whitespaces will be ignored so we don't want to type-check that + // because then type of children property will have constituent of string type. + if (child.kind !== SyntaxKind.JsxTextAllWhiteSpaces) { + childrenTypes.push(child.kind === SyntaxKind.JsxText ? stringType : checkExpression(child as Expression, checkMode)); + } } childrenPropSymbol.type = getUnionType(childrenTypes, /*subtypeReduction*/ false); attributesTable.set(jsxChildrenPropertyName, childrenPropSymbol); @@ -17099,13 +17103,6 @@ namespace ts { return cache ? checkExpressionCached(node) : checkExpression(node); } - // Checks an expression and returns its type. The contextualMapper parameter serves two purposes: When - // contextualMapper is not undefined and not equal to the identityMapper function object it indicates that the - // expression is being inferentially typed (section 4.15.2 in spec) and provides the type mapper to use in - // conjunction with the generic contextual type. When contextualMapper is equal to the identityMapper function - // object, it serves as an indicator that all contained function and arrow expressions should be considered to - // have the wildcard function type; this form of type check is used during overload resolution to exclude - // contextually typed function and arrow expressions in the initial phase. function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode): Type { let type: Type; if (node.kind === SyntaxKind.QualifiedName) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a82d5b02b44..770601bd56c 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3825,7 +3825,7 @@ namespace ts { } function parseJsxText(): JsxText { - const node = createNode(SyntaxKind.JsxText, scanner.getStartPos()); + const node = createNode(currentToken, scanner.getStartPos()); currentToken = scanner.scanJsxToken(); return finishNode(node); } @@ -3833,6 +3833,7 @@ namespace ts { function parseJsxChild(): JsxChild { switch (token()) { case SyntaxKind.JsxText: + case SyntaxKind.JsxTextAllWhiteSpaces: return parseJsxText(); case SyntaxKind.OpenBraceToken: return parseJsxExpression(/*inExpressionContext*/ false); @@ -3862,7 +3863,10 @@ namespace ts { else if (token() === SyntaxKind.ConflictMarkerTrivia) { break; } - result.push(parseJsxChild()); + const child = parseJsxChild(); + if (child) { + result.push(child); + } } result.end = scanner.getTokenPos(); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 7b6e0c09db4..59453f4fa4b 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -1723,6 +1723,11 @@ namespace ts { return token = SyntaxKind.OpenBraceToken; } + // First non-whitespace character on this line. + let firstNonWhitespace = 0; + // These initial values are special because the first line is: + // firstNonWhitespace = 0 to indicate that we want leading whitspace, + while (pos < end) { pos++; char = text.charCodeAt(pos); @@ -1736,8 +1741,22 @@ namespace ts { } break; } + + // FirstNonWhitespace is 0, then we only see whitespaces so far. If we see a linebreak, we want to ignore that whitespaces. + // i.e (- : whitespace) + //
---- + //
becomes
+ // + //
----
becomes
----
+ if (isLineBreak(char) && firstNonWhitespace === 0) { + firstNonWhitespace = -1; + } + else if (!isWhiteSpaceSingleLine(char)) { + firstNonWhitespace = pos; + } } - return token = SyntaxKind.JsxText; + + return firstNonWhitespace === -1 ? SyntaxKind.JsxTextAllWhiteSpaces : SyntaxKind.JsxText; } // Scans a JSX identifier; these differ from normal identifiers in that diff --git a/src/compiler/types.ts b/src/compiler/types.ts index fd246fed821..0e0deeedfaa 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -65,6 +65,7 @@ NumericLiteral, StringLiteral, JsxText, + JsxTextAllWhiteSpaces, RegularExpressionLiteral, NoSubstitutionTemplateLiteral, // Pseudo-literals