Consider whitespace that won't be emitted to be different kind so that we won't include in typ-checking

This commit is contained in:
Kanchalai Tanglertsampan 2017-04-11 10:52:18 -07:00
parent b3846bfe65
commit f86a730371
4 changed files with 33 additions and 12 deletions

View File

@ -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) {

View File

@ -3825,7 +3825,7 @@ namespace ts {
}
function parseJsxText(): JsxText {
const node = <JsxText>createNode(SyntaxKind.JsxText, scanner.getStartPos());
const node = <JsxText>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();

View File

@ -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)
// <div>----
// </div> becomes <div></div>
//
// <div>----</div> becomes <div>----</div>
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

View File

@ -65,6 +65,7 @@
NumericLiteral,
StringLiteral,
JsxText,
JsxTextAllWhiteSpaces,
RegularExpressionLiteral,
NoSubstitutionTemplateLiteral,
// Pseudo-literals