For JSX text, construct a single literal node "foo bar"
instead of "foo" + " " + "bar"
.
This commit is contained in:
parent
7f84953347
commit
87ae723b52
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -42,7 +42,7 @@ var p = 0;
|
||||||
<div>
|
<div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
// Emit "foo" + ' ' + "bar"
|
// Emit "foo bar"
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
foo
|
foo
|
||||||
|
|
Loading…
Reference in a new issue