For JSX text, construct a single literal node "foo bar" instead of "foo" + " " + "bar".

This commit is contained in:
Andy Hanson 2016-09-08 09:50:49 -07:00
parent 7f84953347
commit 87ae723b52
5 changed files with 26 additions and 41 deletions

View file

@ -151,28 +151,29 @@ namespace ts {
} }
} }
function visitJsxText(node: JsxText) { function visitJsxText(node: JsxText): StringLiteral | undefined {
const text = getTextOfNode(node, /*includeTrivia*/ true); const fixed = fixupWhitespaceAndDecodeEntities(getTextOfNode(node, /*includeTrivia*/ true));
let parts: Expression[]; return fixed !== undefined && createLiteral(fixed);
}
/**
* JSX trims whitespace at the end and beginning of lines, except that the
* start/end of a tag is considered a start/end of a line only if that line is
* on the same line as the closing tag. See examples in
* tests/cases/conformance/jsx/tsxReactEmitWhitespace.tsx
* See also https://www.w3.org/TR/html4/struct/text.html#h-9.1 and https://www.w3.org/TR/CSS2/text.html#white-space-model
*/
function fixupWhitespaceAndDecodeEntities(text: string): string | undefined {
let acc: string | undefined;
let firstNonWhitespace = 0; let firstNonWhitespace = 0;
let lastNonWhitespace = -1; let lastNonWhitespace = -1;
// JSX trims whitespace at the end and beginning of lines, except that the
// start/end of a tag is considered a start/end of a line only if that line is
// on the same line as the closing tag. See examples in
// tests/cases/conformance/jsx/tsxReactEmitWhitespace.tsx
for (let i = 0; i < text.length; i++) { for (let i = 0; i < text.length; i++) {
const c = text.charCodeAt(i); const c = text.charCodeAt(i);
if (isLineBreak(c)) { if (isLineBreak(c)) {
if (firstNonWhitespace !== -1 && (lastNonWhitespace - firstNonWhitespace + 1 > 0)) { if (firstNonWhitespace !== -1 && (lastNonWhitespace - firstNonWhitespace + 1 > 0)) {
const part = text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1); const part = decodeEntities(text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1));
if (!parts) { acc = acc === undefined ? part : acc + " " + part;
parts = [];
}
// We do not escape the string here as that is handled by the printer
// when it emits the literal. We do, however, need to decode JSX entities.
parts.push(createLiteral(decodeEntities(part)));
} }
firstNonWhitespace = -1; firstNonWhitespace = -1;
@ -186,28 +187,12 @@ namespace ts {
} }
if (firstNonWhitespace !== -1) { if (firstNonWhitespace !== -1) {
const part = text.substr(firstNonWhitespace); const lastPart = decodeEntities(text.substr(firstNonWhitespace));
if (!parts) { return acc ? acc + lastPart : lastPart;
parts = [];
}
// We do not escape the string here as that is handled by the printer
// when it emits the literal. We do, however, need to decode JSX entities.
parts.push(createLiteral(decodeEntities(part)));
} }
else {
if (parts) { return acc;
return reduceLeft(parts, aggregateJsxTextParts);
} }
return undefined;
}
/**
* Aggregates two expressions by interpolating them with a whitespace literal.
*/
function aggregateJsxTextParts(left: Expression, right: Expression) {
return createAdd(createAdd(left, createLiteral(" ")), right);
} }
/** /**

View file

@ -41,7 +41,7 @@ var p = 0;
<div> <div>
</div>; </div>;
// Emit "foo" + ' ' + "bar" // Emit "foo bar"
<div> <div>
foo foo
@ -75,5 +75,5 @@ React.createElement("div", null, " 3 ");
React.createElement("div", null, "3"); React.createElement("div", null, "3");
// Emit no args // Emit no args
React.createElement("div", null); React.createElement("div", null);
// Emit "foo" + ' ' + "bar" // Emit "foo bar"
React.createElement("div", null, "foo" + " " + "bar"); React.createElement("div", null, "foo bar");

View file

@ -79,7 +79,7 @@ var p = 0;
</div>; </div>;
>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22)) >div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
// Emit "foo" + ' ' + "bar" // Emit "foo bar"
<div> <div>
>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22)) >div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))

View file

@ -88,7 +88,7 @@ var p = 0;
</div>; </div>;
>div : any >div : any
// Emit "foo" + ' ' + "bar" // Emit "foo bar"
<div> <div>
><div> foo bar </div> : JSX.Element ><div> foo bar </div> : JSX.Element
>div : any >div : any

View file

@ -42,7 +42,7 @@ var p = 0;
<div> <div>
</div>; </div>;
// Emit "foo" + ' ' + "bar" // Emit "foo bar"
<div> <div>
foo foo