Merge pull request #6587 from nojvek/master

pretty output for jsx and createElement emits to children array
This commit is contained in:
Daniel Rosenwasser 2016-02-01 21:38:15 -08:00
commit 0855933757
9 changed files with 525 additions and 23 deletions

View file

@ -1263,26 +1263,50 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
// Children
if (children) {
for (let i = 0; i < children.length; i++) {
// Don't emit empty expressions
if (children[i].kind === SyntaxKind.JsxExpression && !((<JsxExpression>children[i]).expression)) {
continue;
}
let firstChild: JsxChild;
let multipleEmittableChildren = false;
// Don't emit empty strings
if (children[i].kind === SyntaxKind.JsxText) {
const text = getTextToEmit(<JsxText>children[i]);
if (text !== undefined) {
write(", \"");
write(text);
write("\"");
for (let i = 0, n = children.length; i < n; i++) {
const jsxChild = children[i];
if (isJsxChildEmittable(jsxChild)) {
// we need to decide whether to emit in single line or multiple lines as indented list
// store firstChild reference, if we see another emittable child, then emit accordingly
if (!firstChild) {
write(", ");
firstChild = jsxChild;
}
else {
// more than one emittable child, emit indented list
if (!multipleEmittableChildren) {
multipleEmittableChildren = true;
increaseIndent();
writeLine();
emit(firstChild);
}
write(", ");
writeLine();
emit(jsxChild);
}
}
else {
write(", ");
emit(children[i]);
}
}
if (multipleEmittableChildren) {
decreaseIndent();
}
else if (firstChild) {
if (firstChild.kind !== SyntaxKind.JsxElement && firstChild.kind !== SyntaxKind.JsxSelfClosingElement) {
emit(firstChild);
}
else {
// If the only child is jsx element, put it on a new indented line
increaseIndent();
writeLine();
emit(firstChild);
writeLine();
decreaseIndent();
}
}
}
@ -7399,7 +7423,21 @@ const _super = (function (geti, seti) {
return result;
}
function getTextToEmit(node: JsxText) {
function isJsxChildEmittable(child: JsxChild): boolean {
if (child.kind === SyntaxKind.JsxExpression) {
// Don't emit empty expressions
return !!(<JsxExpression>child).expression;
}
else if (child.kind === SyntaxKind.JsxText) {
// Don't emit empty strings
return !!getTextToEmit(<JsxText>child);
}
return true;
};
function getTextToEmit(node: JsxText): string {
switch (compilerOptions.jsx) {
case JsxEmit.React:
let text = trimReactWhitespaceAndApplyEntities(node);

View file

@ -70,5 +70,8 @@ var SomeClass = (function () {
return SomeClass;
}());
var whitespace1 = React.createElement("div", null, " ");
var whitespace2 = React.createElement("div", null, " ", p, " ");
var whitespace2 = React.createElement("div", null,
" ",
p,
" ");
var whitespace3 = React.createElement("div", null, p);

View file

@ -8,4 +8,11 @@ declare var Foo, Bar, baz;
<Foo> <Bar> q </Bar> <Bar/> s <Bar/><Bar/></Foo>;
//// [test.js]
React.createElement(Foo, null, " ", React.createElement(Bar, null, " q "), " ", React.createElement(Bar, null), " s ", React.createElement(Bar, null), React.createElement(Bar, null));
React.createElement(Foo, null,
" ",
React.createElement(Bar, null, " q "),
" ",
React.createElement(Bar, null),
" s ",
React.createElement(Bar, null),
React.createElement(Bar, null));

View file

@ -0,0 +1,60 @@
//// [file.tsx]
declare var vdom: any;
declare var ctrl: any;
declare var model: any;
// A simple render function with nesting and control statements
let render = (ctrl, model) =>
<section class="todoapp">
<header class="header">
<h1>todos &lt;x&gt;</h1>
<input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} />
</header>
<section class="main" style={{display:(model.todos && model.todos.length) ? "block" : "none"}}>
<input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/>
<ul class="todo-list">
{model.filteredTodos.map((todo) =>
<li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}>
<div class="view">
{(!todo.editable) ?
<input class="toggle" type="checkbox"></input>
: null
}
<label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label>
<button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button>
<div class="iconBorder">
<div class="icon"/>
</div>
</div>
</li>
)}
</ul>
</section>
</section>
//// [file.js]
// A simple render function with nesting and control statements
var render = function (ctrl, model) {
return vdom.createElement("section", {class: "todoapp"},
vdom.createElement("header", {class: "header"},
vdom.createElement("h1", null, "todos <x>"),
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)})),
vdom.createElement("section", {class: "main", style: { display: (model.todos && model.todos.length) ? "block" : "none" }},
vdom.createElement("input", {class: "toggle-all", type: "checkbox", onChange: ctrl.toggleAll.bind(ctrl)}),
vdom.createElement("ul", {class: "todo-list"}, model.filteredTodos.map(function (todo) {
return vdom.createElement("li", {class: { todo: true, completed: todo.completed, editing: todo == model.editedTodo }},
vdom.createElement("div", {class: "view"},
(!todo.editable) ?
vdom.createElement("input", {class: "toggle", type: "checkbox"})
: null,
vdom.createElement("label", {onDoubleClick: function () { ctrl.editTodo(todo); }}, todo.title),
vdom.createElement("button", {class: "destroy", onClick: ctrl.removeTodo.bind(ctrl, todo)}),
vdom.createElement("div", {class: "iconBorder"},
vdom.createElement("div", {class: "icon"})
))
);
}))));
};

View file

@ -0,0 +1,139 @@
=== tests/cases/conformance/jsx/file.tsx ===
declare var vdom: any;
>vdom : Symbol(vdom, Decl(file.tsx, 1, 11))
declare var ctrl: any;
>ctrl : Symbol(ctrl, Decl(file.tsx, 2, 11))
declare var model: any;
>model : Symbol(model, Decl(file.tsx, 3, 11))
// A simple render function with nesting and control statements
let render = (ctrl, model) =>
>render : Symbol(render, Decl(file.tsx, 6, 3))
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
>model : Symbol(model, Decl(file.tsx, 6, 19))
<section class="todoapp">
>section : Symbol(unknown)
>class : Symbol(unknown)
<header class="header">
>header : Symbol(unknown)
>class : Symbol(unknown)
<h1>todos &lt;x&gt;</h1>
>h1 : Symbol(unknown)
>h1 : Symbol(unknown)
<input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} />
>input : Symbol(unknown)
>class : Symbol(unknown)
>autofocus : Symbol(unknown)
>autocomplete : Symbol(unknown)
>placeholder : Symbol(unknown)
>value : Symbol(unknown)
>model : Symbol(model, Decl(file.tsx, 6, 19))
>onKeyup : Symbol(unknown)
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
>model : Symbol(model, Decl(file.tsx, 6, 19))
</header>
>header : Symbol(unknown)
<section class="main" style={{display:(model.todos && model.todos.length) ? "block" : "none"}}>
>section : Symbol(unknown)
>class : Symbol(unknown)
>style : Symbol(unknown)
>display : Symbol(display, Decl(file.tsx, 12, 38))
>model : Symbol(model, Decl(file.tsx, 6, 19))
>model : Symbol(model, Decl(file.tsx, 6, 19))
<input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/>
>input : Symbol(unknown)
>class : Symbol(unknown)
>type : Symbol(unknown)
>onChange : Symbol(unknown)
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
<ul class="todo-list">
>ul : Symbol(unknown)
>class : Symbol(unknown)
{model.filteredTodos.map((todo) =>
>model : Symbol(model, Decl(file.tsx, 6, 19))
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
<li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}>
>li : Symbol(unknown)
>class : Symbol(unknown)
>todo : Symbol(todo, Decl(file.tsx, 16, 32))
>completed : Symbol(completed, Decl(file.tsx, 16, 43))
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
>editing : Symbol(editing, Decl(file.tsx, 16, 70))
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
>model : Symbol(model, Decl(file.tsx, 6, 19))
<div class="view">
>div : Symbol(unknown)
>class : Symbol(unknown)
{(!todo.editable) ?
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
<input class="toggle" type="checkbox"></input>
>input : Symbol(unknown)
>class : Symbol(unknown)
>type : Symbol(unknown)
>input : Symbol(unknown)
: null
}
<label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label>
>label : Symbol(unknown)
>onDoubleClick : Symbol(unknown)
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
>label : Symbol(unknown)
<button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button>
>button : Symbol(unknown)
>class : Symbol(unknown)
>onClick : Symbol(unknown)
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
>ctrl : Symbol(ctrl, Decl(file.tsx, 6, 14))
>todo : Symbol(todo, Decl(file.tsx, 15, 42))
>button : Symbol(unknown)
<div class="iconBorder">
>div : Symbol(unknown)
>class : Symbol(unknown)
<div class="icon"/>
>div : Symbol(unknown)
>class : Symbol(unknown)
</div>
>div : Symbol(unknown)
</div>
>div : Symbol(unknown)
</li>
>li : Symbol(unknown)
)}
</ul>
>ul : Symbol(unknown)
</section>
>section : Symbol(unknown)
</section>
>section : Symbol(unknown)

View file

@ -0,0 +1,208 @@
=== tests/cases/conformance/jsx/file.tsx ===
declare var vdom: any;
>vdom : any
declare var ctrl: any;
>ctrl : any
declare var model: any;
>model : any
// A simple render function with nesting and control statements
let render = (ctrl, model) =>
>render : (ctrl: any, model: any) => any
>(ctrl, model) => <section class="todoapp"> <header class="header"> <h1>todos &lt;x&gt;</h1> <input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} /> </header> <section class="main" style={{display:(model.todos && model.todos.length) ? "block" : "none"}}> <input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/> <ul class="todo-list"> {model.filteredTodos.map((todo) => <li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}> <div class="view"> {(!todo.editable) ? <input class="toggle" type="checkbox"></input> : null } <label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label> <button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button> <div class="iconBorder"> <div class="icon"/> </div> </div> </li> )} </ul> </section> </section> : (ctrl: any, model: any) => any
>ctrl : any
>model : any
<section class="todoapp">
><section class="todoapp"> <header class="header"> <h1>todos &lt;x&gt;</h1> <input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} /> </header> <section class="main" style={{display:(model.todos && model.todos.length) ? "block" : "none"}}> <input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/> <ul class="todo-list"> {model.filteredTodos.map((todo) => <li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}> <div class="view"> {(!todo.editable) ? <input class="toggle" type="checkbox"></input> : null } <label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label> <button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button> <div class="iconBorder"> <div class="icon"/> </div> </div> </li> )} </ul> </section> </section> : any
>section : any
>class : any
<header class="header">
><header class="header"> <h1>todos &lt;x&gt;</h1> <input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} /> </header> : any
>header : any
>class : any
<h1>todos &lt;x&gt;</h1>
><h1>todos &lt;x&gt;</h1> : any
>h1 : any
>h1 : any
<input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} />
><input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} /> : any
>input : any
>class : any
>autofocus : any
>autocomplete : any
>placeholder : any
>value : any
>model.newTodo : any
>model : any
>newTodo : any
>onKeyup : any
>ctrl.addTodo.bind(ctrl, model) : any
>ctrl.addTodo.bind : any
>ctrl.addTodo : any
>ctrl : any
>addTodo : any
>bind : any
>ctrl : any
>model : any
</header>
>header : any
<section class="main" style={{display:(model.todos && model.todos.length) ? "block" : "none"}}>
><section class="main" style={{display:(model.todos && model.todos.length) ? "block" : "none"}}> <input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/> <ul class="todo-list"> {model.filteredTodos.map((todo) => <li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}> <div class="view"> {(!todo.editable) ? <input class="toggle" type="checkbox"></input> : null } <label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label> <button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button> <div class="iconBorder"> <div class="icon"/> </div> </div> </li> )} </ul> </section> : any
>section : any
>class : any
>style : any
>{display:(model.todos && model.todos.length) ? "block" : "none"} : { display: string; }
>display : string
>(model.todos && model.todos.length) ? "block" : "none" : string
>(model.todos && model.todos.length) : any
>model.todos && model.todos.length : any
>model.todos : any
>model : any
>todos : any
>model.todos.length : any
>model.todos : any
>model : any
>todos : any
>length : any
>"block" : string
>"none" : string
<input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/>
><input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/> : any
>input : any
>class : any
>type : any
>onChange : any
>ctrl.toggleAll.bind(ctrl) : any
>ctrl.toggleAll.bind : any
>ctrl.toggleAll : any
>ctrl : any
>toggleAll : any
>bind : any
>ctrl : any
<ul class="todo-list">
><ul class="todo-list"> {model.filteredTodos.map((todo) => <li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}> <div class="view"> {(!todo.editable) ? <input class="toggle" type="checkbox"></input> : null } <label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label> <button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button> <div class="iconBorder"> <div class="icon"/> </div> </div> </li> )} </ul> : any
>ul : any
>class : any
{model.filteredTodos.map((todo) =>
>model.filteredTodos.map((todo) => <li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}> <div class="view"> {(!todo.editable) ? <input class="toggle" type="checkbox"></input> : null } <label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label> <button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button> <div class="iconBorder"> <div class="icon"/> </div> </div> </li> ) : any
>model.filteredTodos.map : any
>model.filteredTodos : any
>model : any
>filteredTodos : any
>map : any
>(todo) => <li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}> <div class="view"> {(!todo.editable) ? <input class="toggle" type="checkbox"></input> : null } <label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label> <button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button> <div class="iconBorder"> <div class="icon"/> </div> </div> </li> : (todo: any) => any
>todo : any
<li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}>
><li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}> <div class="view"> {(!todo.editable) ? <input class="toggle" type="checkbox"></input> : null } <label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label> <button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button> <div class="iconBorder"> <div class="icon"/> </div> </div> </li> : any
>li : any
>class : any
>{todo: true, completed: todo.completed, editing: todo == model.editedTodo} : { todo: boolean; completed: any; editing: boolean; }
>todo : boolean
>true : boolean
>completed : any
>todo.completed : any
>todo : any
>completed : any
>editing : boolean
>todo == model.editedTodo : boolean
>todo : any
>model.editedTodo : any
>model : any
>editedTodo : any
<div class="view">
><div class="view"> {(!todo.editable) ? <input class="toggle" type="checkbox"></input> : null } <label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label> <button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button> <div class="iconBorder"> <div class="icon"/> </div> </div> : any
>div : any
>class : any
{(!todo.editable) ?
>(!todo.editable) ? <input class="toggle" type="checkbox"></input> : null : any
>(!todo.editable) : boolean
>!todo.editable : boolean
>todo.editable : any
>todo : any
>editable : any
<input class="toggle" type="checkbox"></input>
><input class="toggle" type="checkbox"></input> : any
>input : any
>class : any
>type : any
>input : any
: null
>null : null
}
<label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label>
><label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label> : any
>label : any
>onDoubleClick : any
>()=>{ctrl.editTodo(todo)} : () => void
>ctrl.editTodo(todo) : any
>ctrl.editTodo : any
>ctrl : any
>editTodo : any
>todo : any
>todo.title : any
>todo : any
>title : any
>label : any
<button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button>
><button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button> : any
>button : any
>class : any
>onClick : any
>ctrl.removeTodo.bind(ctrl,todo) : any
>ctrl.removeTodo.bind : any
>ctrl.removeTodo : any
>ctrl : any
>removeTodo : any
>bind : any
>ctrl : any
>todo : any
>button : any
<div class="iconBorder">
><div class="iconBorder"> <div class="icon"/> </div> : any
>div : any
>class : any
<div class="icon"/>
><div class="icon"/> : any
>div : any
>class : any
</div>
>div : any
</div>
>div : any
</li>
>li : any
)}
</ul>
>ul : any
</section>
>section : any
</section>
>section : any

View file

@ -59,7 +59,10 @@ var p = 0;
// Emit " "
React.createElement("div", null, " ");
// Emit " ", p, " "
React.createElement("div", null, " ", p, " ");
React.createElement("div", null,
" ",
p,
" ");
// Emit only p
React.createElement("div", null, p);
// Emit only p

View file

@ -18,8 +18,15 @@ declare var React: any;
//// [file.js]
// Emit ' word' in the last string
React.createElement("div", null, "word ", React.createElement("code", null, "code"), " word");
React.createElement("div", null,
"word ",
React.createElement("code", null, "code"),
" word");
// Same here
React.createElement("div", null, React.createElement("code", null, "code"), " word");
React.createElement("div", null,
React.createElement("code", null, "code"),
" word");
// And here
React.createElement("div", null, React.createElement("code", null), " word");
React.createElement("div", null,
React.createElement("code", null),
" word");

View file

@ -0,0 +1,37 @@
//@filename: file.tsx
//@jsx: react
//@reactNamespace: vdom
declare var vdom: any;
declare var ctrl: any;
declare var model: any;
// A simple render function with nesting and control statements
let render = (ctrl, model) =>
<section class="todoapp">
<header class="header">
<h1>todos &lt;x&gt;</h1>
<input class="new-todo" autofocus autocomplete="off" placeholder="What needs to be done?" value={model.newTodo} onKeyup={ctrl.addTodo.bind(ctrl, model)} />
</header>
<section class="main" style={{display:(model.todos && model.todos.length) ? "block" : "none"}}>
<input class="toggle-all" type="checkbox" onChange={ctrl.toggleAll.bind(ctrl)}/>
<ul class="todo-list">
{model.filteredTodos.map((todo) =>
<li class={{todo: true, completed: todo.completed, editing: todo == model.editedTodo}}>
<div class="view">
{(!todo.editable) ?
<input class="toggle" type="checkbox"></input>
: null
}
<label onDoubleClick={()=>{ctrl.editTodo(todo)}}>{todo.title}</label>
<button class="destroy" onClick={ctrl.removeTodo.bind(ctrl,todo)}></button>
<div class="iconBorder">
<div class="icon"/>
</div>
</div>
</li>
)}
</ul>
</section>
</section>