Skip to content

Commit 0855933

Browse files
Merge pull request microsoft#6587 from nojvek/master
pretty output for jsx and createElement emits to children array
2 parents a17dbd5 + bd86e2e commit 0855933

9 files changed

Lines changed: 524 additions & 22 deletions

File tree

src/compiler/emitter.ts

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,26 +1263,50 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
12631263

12641264
// Children
12651265
if (children) {
1266-
for (let i = 0; i < children.length; i++) {
1267-
// Don't emit empty expressions
1268-
if (children[i].kind === SyntaxKind.JsxExpression && !((<JsxExpression>children[i]).expression)) {
1269-
continue;
1270-
}
1266+
let firstChild: JsxChild;
1267+
let multipleEmittableChildren = false;
12711268

1272-
// Don't emit empty strings
1273-
if (children[i].kind === SyntaxKind.JsxText) {
1274-
const text = getTextToEmit(<JsxText>children[i]);
1275-
if (text !== undefined) {
1276-
write(", \"");
1277-
write(text);
1278-
write("\"");
1269+
for (let i = 0, n = children.length; i < n; i++) {
1270+
const jsxChild = children[i];
1271+
1272+
if (isJsxChildEmittable(jsxChild)) {
1273+
// we need to decide whether to emit in single line or multiple lines as indented list
1274+
// store firstChild reference, if we see another emittable child, then emit accordingly
1275+
if (!firstChild) {
1276+
write(", ");
1277+
firstChild = jsxChild;
12791278
}
1279+
else {
1280+
// more than one emittable child, emit indented list
1281+
if (!multipleEmittableChildren) {
1282+
multipleEmittableChildren = true;
1283+
increaseIndent();
1284+
writeLine();
1285+
emit(firstChild);
1286+
}
1287+
1288+
write(", ");
1289+
writeLine();
1290+
emit(jsxChild);
1291+
}
1292+
}
1293+
}
1294+
1295+
if (multipleEmittableChildren) {
1296+
decreaseIndent();
1297+
}
1298+
else if (firstChild) {
1299+
if (firstChild.kind !== SyntaxKind.JsxElement && firstChild.kind !== SyntaxKind.JsxSelfClosingElement) {
1300+
emit(firstChild);
12801301
}
12811302
else {
1282-
write(", ");
1283-
emit(children[i]);
1303+
// If the only child is jsx element, put it on a new indented line
1304+
increaseIndent();
1305+
writeLine();
1306+
emit(firstChild);
1307+
writeLine();
1308+
decreaseIndent();
12841309
}
1285-
12861310
}
12871311
}
12881312

@@ -7399,7 +7423,21 @@ const _super = (function (geti, seti) {
73997423
return result;
74007424
}
74017425

7402-
function getTextToEmit(node: JsxText) {
7426+
function isJsxChildEmittable(child: JsxChild): boolean {
7427+
if (child.kind === SyntaxKind.JsxExpression) {
7428+
// Don't emit empty expressions
7429+
return !!(<JsxExpression>child).expression;
7430+
7431+
}
7432+
else if (child.kind === SyntaxKind.JsxText) {
7433+
// Don't emit empty strings
7434+
return !!getTextToEmit(<JsxText>child);
7435+
}
7436+
7437+
return true;
7438+
};
7439+
7440+
function getTextToEmit(node: JsxText): string {
74037441
switch (compilerOptions.jsx) {
74047442
case JsxEmit.React:
74057443
let text = trimReactWhitespaceAndApplyEntities(node);

tests/baselines/reference/tsxReactEmit1.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,8 @@ var SomeClass = (function () {
7070
return SomeClass;
7171
}());
7272
var whitespace1 = React.createElement("div", null, " ");
73-
var whitespace2 = React.createElement("div", null, " ", p, " ");
73+
var whitespace2 = React.createElement("div", null,
74+
" ",
75+
p,
76+
" ");
7477
var whitespace3 = React.createElement("div", null, p);

tests/baselines/reference/tsxReactEmit3.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,11 @@ declare var Foo, Bar, baz;
88
<Foo> <Bar> q </Bar> <Bar/> s <Bar/><Bar/></Foo>;
99

1010
//// [test.js]
11-
React.createElement(Foo, null, " ", React.createElement(Bar, null, " q "), " ", React.createElement(Bar, null), " s ", React.createElement(Bar, null), React.createElement(Bar, null));
11+
React.createElement(Foo, null,
12+
" ",
13+
React.createElement(Bar, null, " q "),
14+
" ",
15+
React.createElement(Bar, null),
16+
" s ",
17+
React.createElement(Bar, null),
18+
React.createElement(Bar, null));
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//// [file.tsx]
2+
3+
declare var vdom: any;
4+
declare var ctrl: any;
5+
declare var model: any;
6+
7+
// A simple render function with nesting and control statements
8+
let render = (ctrl, model) =>
9+
<section class="todoapp">
10+
<header class="header">
11+
<h1>todos &lt;x&gt;</h1>
12+
<input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} />
13+
</header>
14+
<section class="main" style={{display:(model.todos && model.todos.length) ? "block" : "none"}}>
15+
<input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/>
16+
<ul class="todo-list">
17+
{model.filteredTodos.map((todo) =>
18+
<li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}>
19+
<div class="view">
20+
{(!todo.editable) ?
21+
<input class="toggle" type="checkbox"></input>
22+
: null
23+
}
24+
<label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label>
25+
<button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button>
26+
<div class="iconBorder">
27+
<div class="icon"/>
28+
</div>
29+
</div>
30+
</li>
31+
)}
32+
</ul>
33+
</section>
34+
</section>
35+
36+
37+
38+
//// [file.js]
39+
// A simple render function with nesting and control statements
40+
var render = function (ctrl, model) {
41+
return vdom.createElement("section", {class: "todoapp"},
42+
vdom.createElement("header", {class: "header"},
43+
vdom.createElement("h1", null, "todos <x>"),
44+
vdom.createElement("input", {class: "new-todo", autofocus: true, autocomplete: "off", placeholder: "What needs to be done?", value: model.newTodo, onKeyup: ctrl.addTodo.bind(ctrl, model)})),
45+
vdom.createElement("section", {class: "main", style: { display: (model.todos && model.todos.length) ? "block" : "none" }},
46+
vdom.createElement("input", {class: "toggle-all", type: "checkbox", onChange: ctrl.toggleAll.bind(ctrl)}),
47+
vdom.createElement("ul", {class: "todo-list"}, model.filteredTodos.map(function (todo) {
48+
return vdom.createElement("li", {class: { todo: true, completed: todo.completed, editing: todo == model.editedTodo }},
49+
vdom.createElement("div", {class: "view"},
50+
(!todo.editable) ?
51+
vdom.createElement("input", {class: "toggle", type: "checkbox"})
52+
: null,
53+
vdom.createElement("label", {onDoubleClick: function () { ctrl.editTodo(todo); }}, todo.title),
54+
vdom.createElement("button", {class: "destroy", onClick: ctrl.removeTodo.bind(ctrl, todo)}),
55+
vdom.createElement("div", {class: "iconBorder"},
56+
vdom.createElement("div", {class: "icon"})
57+
))
58+
);
59+
}))));
60+
};
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
=== tests/cases/conformance/jsx/file.tsx ===
2+
3+
declare var vdom: any;
4+
>vdom : Symbol(vdom, Decl(file.tsx, 1, 11))
5+
6+
declare var ctrl: any;
7+
>ctrl : Symbol(ctrl, Decl(file.tsx, 2, 11))
8+
9+
declare var model: any;
10+
>model : Symbol(model, Decl(file.tsx, 3, 11))
11+
12+
// A simple render function with nesting and control statements
13+
let render = (ctrl, model) =>
14+
>render : Symbol(render, Decl(file.tsx, 6, 3))
15+
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
16+
>model : Symbol(model, Decl(file.tsx, 6, 19))
17+
18+
<section class="todoapp">
19+
>section : Symbol(unknown)
20+
>class : Symbol(unknown)
21+
22+
<header class="header">
23+
>header : Symbol(unknown)
24+
>class : Symbol(unknown)
25+
26+
<h1>todos &lt;x&gt;</h1>
27+
>h1 : Symbol(unknown)
28+
>h1 : Symbol(unknown)
29+
30+
<input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} />
31+
>input : Symbol(unknown)
32+
>class : Symbol(unknown)
33+
>autofocus : Symbol(unknown)
34+
>autocomplete : Symbol(unknown)
35+
>placeholder : Symbol(unknown)
36+
>value : Symbol(unknown)
37+
>model : Symbol(model, Decl(file.tsx, 6, 19))
38+
>onKeyup : Symbol(unknown)
39+
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
40+
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
41+
>model : Symbol(model, Decl(file.tsx, 6, 19))
42+
43+
</header>
44+
>header : Symbol(unknown)
45+
46+
<section class="main" style={{display:(model.todos && model.todos.length) ? "block" : "none"}}>
47+
>section : Symbol(unknown)
48+
>class : Symbol(unknown)
49+
>style : Symbol(unknown)
50+
>display : Symbol(display, Decl(file.tsx, 12, 38))
51+
>model : Symbol(model, Decl(file.tsx, 6, 19))
52+
>model : Symbol(model, Decl(file.tsx, 6, 19))
53+
54+
<input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/>
55+
>input : Symbol(unknown)
56+
>class : Symbol(unknown)
57+
>type : Symbol(unknown)
58+
>onChange : Symbol(unknown)
59+
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
60+
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
61+
62+
<ul class="todo-list">
63+
>ul : Symbol(unknown)
64+
>class : Symbol(unknown)
65+
66+
{model.filteredTodos.map((todo) =>
67+
>model : Symbol(model, Decl(file.tsx, 6, 19))
68+
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
69+
70+
<li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}>
71+
>li : Symbol(unknown)
72+
>class : Symbol(unknown)
73+
>todo : Symbol(todo, Decl(file.tsx, 16, 32))
74+
>completed : Symbol(completed, Decl(file.tsx, 16, 43))
75+
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
76+
>editing : Symbol(editing, Decl(file.tsx, 16, 70))
77+
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
78+
>model : Symbol(model, Decl(file.tsx, 6, 19))
79+
80+
<div class="view">
81+
>div : Symbol(unknown)
82+
>class : Symbol(unknown)
83+
84+
{(!todo.editable) ?
85+
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
86+
87+
<input class="toggle" type="checkbox"></input>
88+
>input : Symbol(unknown)
89+
>class : Symbol(unknown)
90+
>type : Symbol(unknown)
91+
>input : Symbol(unknown)
92+
93+
: null
94+
}
95+
<label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label>
96+
>label : Symbol(unknown)
97+
>onDoubleClick : Symbol(unknown)
98+
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
99+
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
100+
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
101+
>label : Symbol(unknown)
102+
103+
<button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button>
104+
>button : Symbol(unknown)
105+
>class : Symbol(unknown)
106+
>onClick : Symbol(unknown)
107+
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
108+
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
109+
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
110+
>button : Symbol(unknown)
111+
112+
<div class="iconBorder">
113+
>div : Symbol(unknown)
114+
>class : Symbol(unknown)
115+
116+
<div class="icon"/>
117+
>div : Symbol(unknown)
118+
>class : Symbol(unknown)
119+
120+
</div>
121+
>div : Symbol(unknown)
122+
123+
</div>
124+
>div : Symbol(unknown)
125+
126+
</li>
127+
>li : Symbol(unknown)
128+
129+
)}
130+
</ul>
131+
>ul : Symbol(unknown)
132+
133+
</section>
134+
>section : Symbol(unknown)
135+
136+
</section>
137+
>section : Symbol(unknown)
138+
139+

0 commit comments

Comments
 (0)