Glimmer: Improve whitespace handling (#6354)

* Improve curly and whitespace handling

* Refactoring and clean up

* Collapse elements with non-whitespace children

* Clean selfClosing check in AST compare

selfClosing tags can't be considered when using AST_COMPARE=1.
The new AST may have a Glimmer component that has been collapsed,
ie: <HelloWorld></HelloWorld> -> <HelloWorld />

These result in different ASTs and thereofre we need to clean the
check that compares self-closing in the before and after ASTs

Co-authored-by: Jamie White <jamie@jgwhite.co.uk>

* Add istanbul ignore for ternaries in utilities

* Improve handling around whitespace near elements and block statements

* Update tests after rebasing

* Fix CHANGELOG.unreleased.md after rebase

* Tweak regex around leading and trialing line beraks and update test

Co-authored-by: FabHof <35104465+FabHof@users.noreply.github.com>

* Extract attribute value from concat node
master
Chad Carbert 2019-10-21 23:51:41 +02:00 committed by Lipis
parent e4ab962a6d
commit a7cae47cdf
13 changed files with 483 additions and 142 deletions

View File

@ -1037,7 +1037,50 @@ class A {
}} }}
``` ```
[#5682]: https://github.com/prettier/prettier/pull/5682 #### Handlebars: Fix handling of whitespace and line breaks ([#6354] by [@chadian])
This fixes a variety of whitespace and line break usecases within handlebars and Glimmer templates.
<!-- prettier-ignore -->
```hbs
// Input
<SomeComponent />{{name}}
Some sentence with {{dynamic}} expressions.
sometimes{{nogaps}}areimportant<Hello></Hello>
{{name}} is your name
// Output (Prettier stable)
<SomeComponent />
{{name}}
Some sentence with
{{dynamic}}
expressions.
sometimes
{{nogaps}}
areimportant
<Hello />
{{name}}
is your name
// Output (Prettier master)
<SomeComponent />{{name}}
Some sentence with {{dynamic}} expressions.
sometimes{{nogaps}}areimportant
<Hello />
{{name}} is your name
```
[#5910]: https://github.com/prettier/prettier/pull/5910 [#5910]: https://github.com/prettier/prettier/pull/5910
[#6033]: https://github.com/prettier/prettier/pull/6033 [#6033]: https://github.com/prettier/prettier/pull/6033
[#6186]: https://github.com/prettier/prettier/pull/6186 [#6186]: https://github.com/prettier/prettier/pull/6186
@ -1087,3 +1130,4 @@ class A {
[@squidfunk]: https://github.com/squidfunk [@squidfunk]: https://github.com/squidfunk
[@vjeux]: https://github.com/vjeux [@vjeux]: https://github.com/vjeux
[@selvazhagan]: https://github.com/selvazhagan [@selvazhagan]: https://github.com/selvazhagan
[@chadian]: https://github.com/chadian

View File

@ -43,19 +43,11 @@ function printChildren(path, options, print) {
const isWhitespace = isWhitespaceNode(childNode); const isWhitespace = isWhitespaceNode(childNode);
if (isWhitespace && isLastNodeInMultiNodeList) { if (isWhitespace && isLastNodeInMultiNodeList) {
return concat([print(childPath, options, print)]); return print(childPath, options, print);
} else if ( } else if (isFirstNode) {
isFirstNode ||
isPreviousNodeOfSomeType(childPath, [
"ElementNode",
"CommentStatement",
"MustacheCommentStatement",
"BlockStatement"
])
) {
return concat([softline, print(childPath, options, print)]); return concat([softline, print(childPath, options, print)]);
} }
return concat([print(childPath, options, print)]); return print(childPath, options, print);
}, "children") }, "children")
); );
} }
@ -72,9 +64,7 @@ function print(path, options, print) {
case "Block": case "Block":
case "Program": case "Program":
case "Template": { case "Template": {
return group( return group(concat(path.map(print, "body").filter(text => text !== "")));
join(softline, path.map(print, "body").filter(text => text !== ""))
);
} }
case "ElementNode": { case "ElementNode": {
const tagFirstChar = n.tag[0]; const tagFirstChar = n.tag[0];
@ -82,8 +72,14 @@ function print(path, options, print) {
const isGlimmerComponent = const isGlimmerComponent =
tagFirstChar.toUpperCase() === tagFirstChar || isLocal; tagFirstChar.toUpperCase() === tagFirstChar || isLocal;
const hasChildren = n.children.length > 0; const hasChildren = n.children.length > 0;
const hasNonWhitespaceChildren = n.children.some(
n => !isWhitespaceNode(n)
);
const isVoid = const isVoid =
(isGlimmerComponent && !hasChildren) || voidTags.indexOf(n.tag) !== -1; (isGlimmerComponent && (!hasChildren || !hasNonWhitespaceChildren)) ||
voidTags.indexOf(n.tag) !== -1;
const closeTagForNoBreak = isVoid ? concat([" />", softline]) : ">"; const closeTagForNoBreak = isVoid ? concat([" />", softline]) : ">";
const closeTagForBreak = isVoid ? "/>" : ">"; const closeTagForBreak = isVoid ? "/>" : ">";
const getParams = (path, print) => const getParams = (path, print) =>
@ -100,6 +96,8 @@ function print(path, options, print) {
]) ])
); );
const nextNode = getNextNode(path);
return concat([ return concat([
group( group(
concat([ concat([
@ -111,13 +109,18 @@ function print(path, options, print) {
ifBreak(closeTagForBreak, closeTagForNoBreak) ifBreak(closeTagForBreak, closeTagForNoBreak)
]) ])
), ),
group( !isVoid
concat([ ? group(
indent(printChildren(path, options, print)), concat([
ifBreak(hasChildren ? hardline : "", ""), hasNonWhitespaceChildren
!isVoid ? concat(["</", n.tag, ">"]) : "" ? indent(printChildren(path, options, print))
]) : "",
) ifBreak(hasChildren ? hardline : "", ""),
concat(["</", n.tag, ">"])
])
)
: "",
nextNode && nextNode.type === "ElementNode" ? hardline : ""
]); ]);
} }
case "BlockStatement": { case "BlockStatement": {
@ -156,6 +159,7 @@ function print(path, options, print) {
const hasNonWhitespaceChildren = n.program.body.some( const hasNonWhitespaceChildren = n.program.body.some(
n => !isWhitespaceNode(n) n => !isWhitespaceNode(n)
); );
return concat([ return concat([
printOpenBlock(path, print), printOpenBlock(path, print),
group( group(
@ -196,7 +200,9 @@ function print(path, options, print) {
return concat([n.name]); return concat([n.name]);
} }
const value = path.call(print, "value"); const value = path.call(print, "value");
const quotedValue = isText ? printStringLiteral(value, options) : value; const quotedValue = isText
? printStringLiteral(value.parts.join(), options)
: value;
return concat([n.name, "=", quotedValue]); return concat([n.name, "=", quotedValue]);
} }
case "ConcatStatement": { case "ConcatStatement": {
@ -222,25 +228,54 @@ function print(path, options, print) {
return concat([n.key, "=", path.call(print, "value")]); return concat([n.key, "=", path.call(print, "value")]);
} }
case "TextNode": { case "TextNode": {
const maxLineBreaksToPreserve = 2;
const isFirstElement = !getPreviousNode(path);
const isLastElement = !getNextNode(path);
const isWhitespaceOnly = !/\S/.test(n.chars); const isWhitespaceOnly = !/\S/.test(n.chars);
const lineBreaksCount = countNewLines(n.chars);
const hasBlockParent = path.getParentNode(0).type === "Block";
const hasElementParent = path.getParentNode(0).type === "ElementNode";
const hasTemplateParent = path.getParentNode(0).type === "Template";
let leadingLineBreaksCount = countLeadingNewLines(n.chars);
let trailingLineBreaksCount = countTrailingNewLines(n.chars);
if ( if (
(isFirstElement || isLastElement) &&
isWhitespaceOnly && isWhitespaceOnly &&
isPreviousNodeOfSomeType(path, ["MustacheStatement", "TextNode"]) (hasBlockParent || hasElementParent || hasTemplateParent)
) { ) {
return " "; return "";
}
if (isWhitespaceOnly && lineBreaksCount) {
leadingLineBreaksCount = Math.min(
lineBreaksCount,
maxLineBreaksToPreserve
);
trailingLineBreaksCount = 0;
} else {
if (
isNextNodeOfType(path, "ElementNode") ||
isNextNodeOfType(path, "BlockStatement")
) {
trailingLineBreaksCount = Math.max(trailingLineBreaksCount, 1);
}
if (
isPreviousNodeOfSomeType(path, ["ElementNode"]) ||
isPreviousNodeOfSomeType(path, ["BlockStatement"])
) {
leadingLineBreaksCount = Math.max(leadingLineBreaksCount, 1);
}
} }
let leadingSpace = ""; let leadingSpace = "";
let trailingSpace = ""; let trailingSpace = "";
if (isNextNodeOfType(path, "MustacheStatement")) { // preserve a space inside of an attribute node where whitespace present,
trailingSpace = " "; // when next to mustache statement.
}
// preserve a space inside of an attribute node where whitespace present, when next to mustache statement.
const inAttrNode = path.stack.indexOf("attributes") >= 0; const inAttrNode = path.stack.indexOf("attributes") >= 0;
if (inAttrNode) { if (inAttrNode) {
const parentNode = path.getParentNode(0); const parentNode = path.getParentNode(0);
const isConcat = parentNode.type === "ConcatStatement"; const isConcat = parentNode.type === "ConcatStatement";
@ -262,10 +297,41 @@ function print(path, options, print) {
} }
} }
} }
} else {
if (
trailingLineBreaksCount === 0 &&
isNextNodeOfType(path, "MustacheStatement")
) {
trailingSpace = " ";
}
if (
leadingLineBreaksCount === 0 &&
isPreviousNodeOfSomeType(path, ["MustacheStatement"])
) {
leadingSpace = " ";
}
if (isFirstElement) {
leadingLineBreaksCount = 0;
leadingSpace = "";
}
if (isLastElement) {
trailingLineBreaksCount = 0;
trailingSpace = "";
}
} }
return n.chars
.replace(/^\s+/, leadingSpace) return concat(
.replace(/\s+$/, trailingSpace); [
...generateHardlines(leadingLineBreaksCount, maxLineBreaksToPreserve),
n.chars
.replace(/^[\s ]+/g, leadingSpace)
.replace(/[\s ]+$/, trailingSpace),
...generateHardlines(trailingLineBreaksCount, maxLineBreaksToPreserve)
].filter(Boolean)
);
} }
case "MustacheCommentStatement": { case "MustacheCommentStatement": {
const dashes = n.value.indexOf("}}") > -1 ? "--" : ""; const dashes = n.value.indexOf("}}") > -1 ? "--" : "";
@ -405,7 +471,7 @@ function getPreviousNode(path) {
const node = path.getValue(); const node = path.getValue();
const parentNode = path.getParentNode(0); const parentNode = path.getParentNode(0);
const children = parentNode.children; const children = parentNode.children || parentNode.body;
if (children) { if (children) {
const nodeIndex = children.indexOf(node); const nodeIndex = children.indexOf(node);
if (nodeIndex > 0) { if (nodeIndex > 0) {
@ -419,7 +485,7 @@ function getNextNode(path) {
const node = path.getValue(); const node = path.getValue();
const parentNode = path.getParentNode(0); const parentNode = path.getParentNode(0);
const children = parentNode.children; const children = parentNode.children || parentNode.body;
if (children) { if (children) {
const nodeIndex = children.indexOf(node); const nodeIndex = children.indexOf(node);
if (nodeIndex < children.length) { if (nodeIndex < children.length) {
@ -445,6 +511,7 @@ function isNextNodeOfType(path, type) {
function clean(ast, newObj) { function clean(ast, newObj) {
delete newObj.loc; delete newObj.loc;
delete newObj.selfClosing;
// (Glimmer/HTML) ignore TextNode whitespace // (Glimmer/HTML) ignore TextNode whitespace
if (ast.type === "TextNode") { if (ast.type === "TextNode") {
@ -455,6 +522,30 @@ function clean(ast, newObj) {
} }
} }
function countNewLines(string) {
/* istanbul ignore next */
string = typeof string === "string" ? string : "";
return string.split("\n").length - 1;
}
function countLeadingNewLines(string) {
/* istanbul ignore next */
string = typeof string === "string" ? string : "";
const newLines = (string.match(/^([^\S\r\n]*[\r\n])+/g) || [])[0] || "";
return countNewLines(newLines);
}
function countTrailingNewLines(string) {
/* istanbul ignore next */
string = typeof string === "string" ? string : "";
const newLines = (string.match(/([\r\n][^\S\r\n]*)+$/g) || [])[0] || "";
return countNewLines(newLines);
}
function generateHardlines(number = 0, max = 0) {
return new Array(Math.min(number, max)).fill(hardline);
}
module.exports = { module.exports = {
print, print,
massageAstNode: clean massageAstNode: clean

View File

@ -0,0 +1,44 @@
<SomeComponent />
{{name}}
Some sentence with {{dynamic}} expressions.
sometimes{{nogaps}}areimportant<Hello></Hello>
{{name}} is your name
{{#block}}
{{/block}}
{{#block}}
some {{text}}
{{/block}}
{{#block}}
some {{text}}
{{/block}}
<HelloWorld>
</HelloWorld>
<HelloWorld>
some {{text}}
</HelloWorld>
<HelloWorld>
some {{text}}
</HelloWorld>
<div class="a list of classes">
</div>
<div class="a list of classes">
</div>

View File

@ -28,6 +28,7 @@ printWidth: 80
</div> </div>
</div> </div>
</script> </script>
<div class="{{hello}} {{world}}"></div> <div class="{{hello}} {{world}}"></div>
================================================================================ ================================================================================
`; `;
@ -61,6 +62,7 @@ singleQuote: true
</div> </div>
</div> </div>
</script> </script>
<div class="{{hello}} {{world}}"></div> <div class="{{hello}} {{world}}"></div>
================================================================================ ================================================================================
`; `;
@ -99,28 +101,33 @@ printWidth: 80
=====================================output===================================== =====================================output=====================================
<UserGreeting @name="Ricardo" @greeting="Olá" /> <UserGreeting @name="Ricardo" @greeting="Olá" />
{{@greeting}} {{@greeting}}, {{@name}}!
,
{{@name}}
!
<div> <div>
<UserGreeting <UserGreeting
@aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}} @aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}}
/> />
</div> </div>
<Form as |f|> <Form as |f|>
<f.input @title="hello" /> <f.input @title="hello" />
<f.input> <f.input>
hello hello
</f.input> </f.input>
</Form> </Form>
<this.label @title="hello" /> <this.label @title="hello" />
<button onclick={{action next}}> <button onclick={{action next}}>
Next Next
</button> </button>
<button disabled class="disabled"></button> <button disabled class="disabled"></button>
<button disabled="disabled" class="disabled"></button> <button disabled="disabled" class="disabled"></button>
<img alt="" /> <img alt="" />
<div ...attributes> <div ...attributes>
Hello Hello
</div> </div>
@ -162,28 +169,33 @@ singleQuote: true
=====================================output===================================== =====================================output=====================================
<UserGreeting @name='Ricardo' @greeting='Olá' /> <UserGreeting @name='Ricardo' @greeting='Olá' />
{{@greeting}} {{@greeting}}, {{@name}}!
,
{{@name}}
!
<div> <div>
<UserGreeting <UserGreeting
@aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}} @aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}}
/> />
</div> </div>
<Form as |f|> <Form as |f|>
<f.input @title='hello' /> <f.input @title='hello' />
<f.input> <f.input>
hello hello
</f.input> </f.input>
</Form> </Form>
<this.label @title='hello' /> <this.label @title='hello' />
<button onclick={{action next}}> <button onclick={{action next}}>
Next Next
</button> </button>
<button disabled class='disabled'></button> <button disabled class='disabled'></button>
<button disabled='disabled' class='disabled'></button> <button disabled='disabled' class='disabled'></button>
<img alt='' /> <img alt='' />
<div ...attributes> <div ...attributes>
Hello Hello
</div> </div>
@ -264,6 +276,7 @@ printWidth: 80
<h2> <h2>
By {{author.name}} By {{author.name}}
</h2> </h2>
<div class="body"> <div class="body">
{{body}} {{body}}
</div> </div>
@ -295,6 +308,7 @@ singleQuote: true
<h2> <h2>
By {{author.name}} By {{author.name}}
</h2> </h2>
<div class='body'> <div class='body'>
{{body}} {{body}}
</div> </div>

View File

@ -63,11 +63,13 @@ printWidth: 80
{{#block param hashKey=hashValue as |blockParam|}} {{#block param hashKey=hashValue as |blockParam|}}
Hello Hello
{{/block}} {{/block}}
{{#block {{#block
almost80CharacterLongPositionalParamThatIsFirstAlmost80Chars almost80CharacterLongPositionalParamThatIsFirstAlmost80Chars
helloWorldParam helloWorldParam
key=here key=here
}}{{/block}} }}{{/block}}
{{#block {{#block
param param
param param
@ -80,6 +82,7 @@ printWidth: 80
}} }}
Hello Hello
{{/block}} {{/block}}
{{#block {{#block
param param
param param
@ -93,6 +96,7 @@ printWidth: 80
}} }}
Hello Hello
{{/block}} {{/block}}
{{#block {{#block
param param
param param
@ -110,6 +114,7 @@ printWidth: 80
}} }}
Hello Hello
{{/block}} {{/block}}
{{#block {{#block
hashKey=HashValue hashKey=HashValue
hashKey=hashValue hashKey=hashValue
@ -119,27 +124,33 @@ printWidth: 80
}} }}
Hello Hello
{{/block}} {{/block}}
{{#block}} {{#block}}
{{#block}} {{#block}}
hello hello
{{/block}} {{/block}}
{{/block}} {{/block}}
{{#block}} {{#block}}
{{#block param}} {{#block param}}
hello hello
{{/block}} {{/block}}
{{/block}} {{/block}}
{{#block param}} {{#block param}}
{{#block param}} {{#block param}}
hello hello
{{/block}} {{/block}}
{{/block}} {{/block}}
{{#block}} {{#block}}
hello hello
{{/block}} {{/block}}
<MyComponent as |firstName|> <MyComponent as |firstName|>
{{firstName}} {{firstName}}
</MyComponent> </MyComponent>
<MyComponent as |firstName lastName|> <MyComponent as |firstName lastName|>
{{firstName}} {{lastName}} {{firstName}} {{lastName}}
</MyComponent> </MyComponent>
@ -210,11 +221,13 @@ singleQuote: true
{{#block param hashKey=hashValue as |blockParam|}} {{#block param hashKey=hashValue as |blockParam|}}
Hello Hello
{{/block}} {{/block}}
{{#block {{#block
almost80CharacterLongPositionalParamThatIsFirstAlmost80Chars almost80CharacterLongPositionalParamThatIsFirstAlmost80Chars
helloWorldParam helloWorldParam
key=here key=here
}}{{/block}} }}{{/block}}
{{#block {{#block
param param
param param
@ -227,6 +240,7 @@ singleQuote: true
}} }}
Hello Hello
{{/block}} {{/block}}
{{#block {{#block
param param
param param
@ -240,6 +254,7 @@ singleQuote: true
}} }}
Hello Hello
{{/block}} {{/block}}
{{#block {{#block
param param
param param
@ -257,6 +272,7 @@ singleQuote: true
}} }}
Hello Hello
{{/block}} {{/block}}
{{#block {{#block
hashKey=HashValue hashKey=HashValue
hashKey=hashValue hashKey=hashValue
@ -266,27 +282,33 @@ singleQuote: true
}} }}
Hello Hello
{{/block}} {{/block}}
{{#block}} {{#block}}
{{#block}} {{#block}}
hello hello
{{/block}} {{/block}}
{{/block}} {{/block}}
{{#block}} {{#block}}
{{#block param}} {{#block param}}
hello hello
{{/block}} {{/block}}
{{/block}} {{/block}}
{{#block param}} {{#block param}}
{{#block param}} {{#block param}}
hello hello
{{/block}} {{/block}}
{{/block}} {{/block}}
{{#block}} {{#block}}
hello hello
{{/block}} {{/block}}
<MyComponent as |firstName|> <MyComponent as |firstName|>
{{firstName}} {{firstName}}
</MyComponent> </MyComponent>
<MyComponent as |firstName lastName|> <MyComponent as |firstName lastName|>
{{firstName}} {{lastName}} {{firstName}} {{lastName}}
</MyComponent> </MyComponent>
@ -471,6 +493,7 @@ printWidth: 80
Go to bed! Go to bed!
{{/if}} {{/if}}
</h1> </h1>
<h2> <h2>
{{#if a}} {{#if a}}
A A
@ -478,6 +501,7 @@ printWidth: 80
B B
{{/if}} {{/if}}
</h2> </h2>
{{#if a}} {{#if a}}
b b
{{else if c}} {{else if c}}
@ -485,6 +509,7 @@ printWidth: 80
{{else}} {{else}}
e e
{{/if}} {{/if}}
{{#if a}} {{#if a}}
b b
{{else if c}} {{else if c}}
@ -496,6 +521,7 @@ printWidth: 80
{{/if}} {{/if}}
e e
{{/if}} {{/if}}
{{#if a}} {{#if a}}
b b
{{else if c}} {{else if c}}
@ -507,6 +533,7 @@ printWidth: 80
{{else}} {{else}}
j j
{{/if}} {{/if}}
<div> <div>
{{#if a}} {{#if a}}
b b
@ -516,6 +543,7 @@ printWidth: 80
e e
{{/if}} {{/if}}
</div> </div>
<div> <div>
<div> <div>
{{#if a}} {{#if a}}
@ -527,6 +555,7 @@ printWidth: 80
{{/if}} {{/if}}
</div> </div>
</div> </div>
{{#if a}} {{#if a}}
b b
{{else}} {{else}}
@ -534,6 +563,7 @@ printWidth: 80
e e
{{/each}} {{/each}}
{{/if}} {{/if}}
{{#if a}} {{#if a}}
{{#if b}} {{#if b}}
ab ab
@ -541,6 +571,7 @@ printWidth: 80
ac ac
{{/if}} {{/if}}
{{/if}} {{/if}}
{{#if a}} {{#if a}}
a a
<div> <div>
@ -684,6 +715,7 @@ singleQuote: true
Go to bed! Go to bed!
{{/if}} {{/if}}
</h1> </h1>
<h2> <h2>
{{#if a}} {{#if a}}
A A
@ -691,6 +723,7 @@ singleQuote: true
B B
{{/if}} {{/if}}
</h2> </h2>
{{#if a}} {{#if a}}
b b
{{else if c}} {{else if c}}
@ -698,6 +731,7 @@ singleQuote: true
{{else}} {{else}}
e e
{{/if}} {{/if}}
{{#if a}} {{#if a}}
b b
{{else if c}} {{else if c}}
@ -709,6 +743,7 @@ singleQuote: true
{{/if}} {{/if}}
e e
{{/if}} {{/if}}
{{#if a}} {{#if a}}
b b
{{else if c}} {{else if c}}
@ -720,6 +755,7 @@ singleQuote: true
{{else}} {{else}}
j j
{{/if}} {{/if}}
<div> <div>
{{#if a}} {{#if a}}
b b
@ -729,6 +765,7 @@ singleQuote: true
e e
{{/if}} {{/if}}
</div> </div>
<div> <div>
<div> <div>
{{#if a}} {{#if a}}
@ -740,6 +777,7 @@ singleQuote: true
{{/if}} {{/if}}
</div> </div>
</div> </div>
{{#if a}} {{#if a}}
b b
{{else}} {{else}}
@ -747,6 +785,7 @@ singleQuote: true
e e
{{/each}} {{/each}}
{{/if}} {{/if}}
{{#if a}} {{#if a}}
{{#if b}} {{#if b}}
ab ab
@ -754,6 +793,7 @@ singleQuote: true
ac ac
{{/if}} {{/if}}
{{/if}} {{/if}}
{{#if a}} {{#if a}}
a a
<div> <div>

View File

@ -30,11 +30,13 @@ printWidth: 80
{{#if @foo}} {{#if @foo}}
Foo Foo
{{/if}} {{/if}}
{{! Bar }} {{! Bar }}
{{#if @bar}} {{#if @bar}}
Bar Bar
{{/if}} {{/if}}
</div> </div>
<div class="entry"> <div class="entry">
{{! This comment will not be in the output }} {{! This comment will not be in the output }}
{{!-- This comment as }} and will not be in the output --}} {{!-- This comment as }} and will not be in the output --}}

View File

@ -30,6 +30,7 @@ printWidth: 80
<div class="hello {{if goodbye true}}"> <div class="hello {{if goodbye true}}">
Hello Hello
</div> </div>
<div <div
class="hello class="hello
{{if goodbye true}} {{if goodbye true}}
@ -44,7 +45,9 @@ printWidth: 80
> >
Hello Hello
</div> </div>
<a href="/{{url}}/{{url}}"></a> <a href="/{{url}}/{{url}}"></a>
<div class="class-a{{myClass}}"></div> <div class="class-a{{myClass}}"></div>
<div class="class-b {{myClass}}"></div> <div class="class-b {{myClass}}"></div>
<div class="{{myClass}}class-c"></div> <div class="{{myClass}}class-c"></div>
@ -89,6 +92,7 @@ singleQuote: true
<div class="hello {{if goodbye true}}"> <div class="hello {{if goodbye true}}">
Hello Hello
</div> </div>
<div <div
class="hello class="hello
{{if goodbye true}} {{if goodbye true}}
@ -103,7 +107,9 @@ singleQuote: true
> >
Hello Hello
</div> </div>
<a href="/{{url}}/{{url}}"></a> <a href="/{{url}}/{{url}}"></a>
<div class="class-a{{myClass}}"></div> <div class="class-a{{myClass}}"></div>
<div class="class-b {{myClass}}"></div> <div class="class-b {{myClass}}"></div>
<div class="{{myClass}}class-c"></div> <div class="{{myClass}}class-c"></div>

View File

@ -47,29 +47,37 @@ printWidth: 80
<div class="attribute" {{modifier}} {{! comment}}> <div class="attribute" {{modifier}} {{! comment}}>
Hello Hello
</div> </div>
<div> <div>
Hello Hello
</div> </div>
<div> <div>
hi hi
</div> </div>
<div> <div>
A long enough string to trigger a line break that would prevent wrapping. A long enough string to trigger a line break that would prevent wrapping.
</div> </div>
<div> <div>
A long enough string to trigger a line break that would prevent wrapping more. A long enough string to trigger a line break that would prevent wrapping more.
</div> </div>
<div> <div>
A long enough string to trigger a line break that would prevent wrapping more and more. A long enough string to trigger a line break that would prevent wrapping more and more.
</div> </div>
<div> <div>
{{#block}} {{#block}}
{{hello}} {{hello}}
{{/block}} {{/block}}
</div> </div>
<div> <div>
{{hello}} {{hello}}
</div> </div>
<div></div> <div></div>
<img /> <img />
================================================================================ ================================================================================
@ -123,29 +131,37 @@ singleQuote: true
<div class='attribute' {{modifier}} {{! comment}}> <div class='attribute' {{modifier}} {{! comment}}>
Hello Hello
</div> </div>
<div> <div>
Hello Hello
</div> </div>
<div> <div>
hi hi
</div> </div>
<div> <div>
A long enough string to trigger a line break that would prevent wrapping. A long enough string to trigger a line break that would prevent wrapping.
</div> </div>
<div> <div>
A long enough string to trigger a line break that would prevent wrapping more. A long enough string to trigger a line break that would prevent wrapping more.
</div> </div>
<div> <div>
A long enough string to trigger a line break that would prevent wrapping more and more. A long enough string to trigger a line break that would prevent wrapping more and more.
</div> </div>
<div> <div>
{{#block}} {{#block}}
{{hello}} {{hello}}
{{/block}} {{/block}}
</div> </div>
<div> <div>
{{hello}} {{hello}}
</div> </div>
<div></div> <div></div>
<img /> <img />
================================================================================ ================================================================================

View File

@ -26,6 +26,7 @@ printWidth: 80
<div {{hello param hash=key}} {{goodbye param}}> <div {{hello param hash=key}} {{goodbye param}}>
Hello Hello
</div> </div>
<div <div
{{hello {{hello
param param
@ -44,6 +45,7 @@ printWidth: 80
> >
Hello Hello
</div> </div>
<div <div
{{hello {{hello
hashPair=value hashPair=value
@ -55,6 +57,7 @@ printWidth: 80
> >
Hello Hello
</div> </div>
<div <div
{{hello {{hello
param param
@ -100,6 +103,7 @@ singleQuote: true
<div {{hello param hash=key}} {{goodbye param}}> <div {{hello param hash=key}} {{goodbye param}}>
Hello Hello
</div> </div>
<div <div
{{hello {{hello
param param
@ -118,6 +122,7 @@ singleQuote: true
> >
Hello Hello
</div> </div>
<div <div
{{hello {{hello
hashPair=value hashPair=value
@ -129,6 +134,7 @@ singleQuote: true
> >
Hello Hello
</div> </div>
<div <div
{{hello {{hello
param param

View File

@ -78,12 +78,14 @@ printWidth: 80
=====================================output===================================== =====================================output=====================================
<p> <p>
Welcome to the<strong> Welcome to the
<strong>
Ember.js Guides Ember.js Guides
</strong> </strong>
. .
This documentation will take you from total beginner to Ember expert. This documentation will take you from total beginner to Ember expert.
</p> </p>
{{! newlines text }} {{! newlines text }}
<div> <div>
hi hi
@ -95,39 +97,52 @@ printWidth: 80
are you fine today? are you fine today?
</div> </div>
{{! newlines text spaced }} {{! newlines text spaced }}
<div> <div>
space above space above
space below space below
</div> </div>
{{! newlines elems spaced }} {{! newlines elems spaced }}
<div> <div>
<span> <span>
space above space above
</span> </span>
<span> <span>
space below space below
</span> </span>
</div> </div>
{{! newlines mixed }} {{! newlines mixed }}
<div> <div>
hi<span> hi
<span>
there there
</span> </span>
how how
are<strong> are
<strong>
you you
</strong> </strong>
are you fine today? are you fine today?
</div> </div>
{{! newlines elems }} {{! newlines elems }}
<div> <div>
<div> <div>
<div></div> <div></div>
</div> </div>
hi<div></div>
hi
<div></div>
<Big /> <Big />
</div> </div>
================================================================================ ================================================================================

View File

@ -63,6 +63,7 @@ printWidth: 80
) )
}} }}
></div> ></div>
{{#block {{#block
(concat (concat
(service) (service)
@ -84,6 +85,7 @@ printWidth: 80
hashPair=(does not need a line break due to being under 80 chars long) hashPair=(does not need a line break due to being under 80 chars long)
) )
}}{{/block}} }}{{/block}}
{{foobar-sub-component/foobar-foo {{foobar-sub-component/foobar-foo
hook="stringLiteral" hook="stringLiteral"
foo=(t foo=(t
@ -160,6 +162,7 @@ singleQuote: true
) )
}} }}
></div> ></div>
{{#block {{#block
(concat (concat
(service) (service)
@ -181,6 +184,7 @@ singleQuote: true
hashPair=(does not need a line break due to being under 80 chars long) hashPair=(does not need a line break due to being under 80 chars long)
) )
}}{{/block}} }}{{/block}}
{{foobar-sub-component/foobar-foo {{foobar-sub-component/foobar-foo
hook='stringLiteral' hook='stringLiteral'
foo=(t foo=(t

View File

@ -157,6 +157,34 @@ printWidth: 80
<div> <div>
Some text that would need to wrap on to a new line in order to display correctly and nicely Some text that would need to wrap on to a new line in order to display correctly and nicely
</div> </div>
{{! Wrapping tags }}
<div>
<first>
f
</first>
<first>
f
</first>
<first>
f
</first>
<first>
f
</first>
<first>
f
</first>
<first>
f
</first>
</div>
{{! Wrapping tags }} {{! Wrapping tags }}
<div> <div>
<first> <first>
@ -178,121 +206,125 @@ printWidth: 80
f f
</first> </first>
</div> </div>
{{! Wrapping tags }}
<div>
<first>
f
</first>
<first>
f
</first>
<first>
f
</first>
<first>
f
</first>
<first>
f
</first>
<first>
f
</first>
</div>
{{! Wrapping tags }} {{! Wrapping tags }}
<div> <div>
<first> <first>
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</first> </first>
<first> <first>
f f
</first> </first>
</div> </div>
<div> <div>
before<div> before
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at mollis lorem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at mollis lorem.
</div> </div>
after after
</div> </div>
<div> <div>
before{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{stuff}{stuff}{stuff}after{stuff}after before{stuff}after{stuff}after{stuff}after{stuff}after{stuff}after{stuff}{stuff}{stuff}after{stuff}after
</div> </div>
<div> <div>
before {{stuff}}after {{stuff}}after {{stuff}}after {{stuff}}after {{stuff before {{stuff}} after {{stuff}} after {{stuff}} after {{stuff}} after {{stuff
}}after {{stuff}} {{stuff}} {{stuff}}after {{stuff}}after }} after {{stuff}} {{stuff}} {{stuff}} after {{stuff}} after
</div> </div>
<div> <div>
Please state your<b> Please state your
<b>
name name
</b> </b>
and<b> and
<b>
occupation occupation
</b> </b>
for the board of<b> for the board of
<b>
school school
</b> </b>
directors. directors.
</div> </div>
<div> <div>
First second third<div First second third
<div
attr="a very long string attribute that will overflow because it is very long" attr="a very long string attribute that will overflow because it is very long"
> >
Something Something
</div> </div>
</div> </div>
<div> <div>
<div> <div>
First First
</div> </div>
Second<div> Second
<div>
Third Third
</div> </div>
</div> </div>
<div> <div>
First<div> First
<div>
Second Second
</div> </div>
Third Third
</div> </div>
{{! leading whitespace }} {{! leading whitespace }}
<div> <div>
First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth Thirteenth Fourteenth First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth Thirteenth Fourteenth
</div> </div>
{{! trailing whitespace }} {{! trailing whitespace }}
<div> <div>
First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth Thirteenth Fourteenth First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth Thirteenth Fourteenth
</div> </div>
{{! no leading or trailing whitespace }} {{! no leading or trailing whitespace }}
<div> <div>
First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth Thirteenth Fourteenth First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh Twelfth Thirteenth Fourteenth
</div> </div>
{{! translation leave text around tag }} {{! translation leave text around tag }}
<div> <div>
<span> <span>
First First
</span> </span>
, ,
(<span> (
<span>
Second Second
</span> </span>
) )
</div> </div>
<div> <div>
<span> <span>
First second third fourth fifth sixth seventh First second third fourth fifth sixth seventh
</span> </span>
, ,
(<span> (
<span>
Second Second
</span> </span>
) )
</div> </div>
{{! this really should split across lines }} {{! this really should split across lines }}
<div> <div>
before{{stuff}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff before{{stuff}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff
}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff }}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff
}}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff}}after }}after{{stuff}}after{{stuff}}after{{stuff}}after{{stuff}}after
</div> </div>
{{! solitary whitespace }} {{! solitary whitespace }}
<div <div
first="first" first="first"
@ -302,30 +334,36 @@ printWidth: 80
fifth="fifth" fifth="fifth"
sixth="sixth" sixth="sixth"
> >
</div> </div>
{{! whitespace on newline }} {{! whitespace on newline }}
<div> <div>
<div> <div>
First First
</div> </div>
<div> <div>
Second Second
</div> </div>
<div> <div>
Third Third
</div> </div>
</div> </div>
{{! around multiline element }} {{! around multiline element }}
<div> <div>
Before<div> Before
<div>
{"Enough text to make this element wrap on to multiple lines when formatting"} {"Enough text to make this element wrap on to multiple lines when formatting"}
</div> </div>
After After
</div> </div>
{{! around multiline element second pass }} {{! around multiline element second pass }}
<div> <div>
Before{" "}<div> Before{" "}
<div>
{ {
"Enough text to make this element wrap on to multiple lines when formatting" "Enough text to make this element wrap on to multiple lines when formatting"
} }
@ -333,34 +371,45 @@ printWidth: 80
{" "} {" "}
After After
</div> </div>
{{! dont preserve blank lines when contains text }} {{! dont preserve blank lines when contains text }}
<div> <div>
<div> <div>
Zeroth Zeroth
</div> </div>
<div> <div>
First First
</div> </div>
Second Second
</div> </div>
{{! multiple expressions }} {{! multiple expressions }}
<div> <div>
{{header}} {{body}} {{footer}} {{header}}
{{body}}
{{footer}}
</div> </div>
{{! single expression child tags }} {{! single expression child tags }}
<div> <div>
You currently have<strong> You currently have
<strong>
{{dashboardStr}} {{dashboardStr}}
</strong> </strong>
and<strong> and
<strong>
{{userStr}} {{userStr}}
</strong> </strong>
</div> </div>
{{! expression does not break }} {{! expression does not break }}
<div> <div>
texty text text text text text text text text text text text {{this.props.type texty text text text text text text text text text text text {{this.props.type
}} }}
</div> </div>
// FIXME // FIXME
================================================================================ ================================================================================
`; `;

View File

@ -36,10 +36,12 @@ printWidth: 40
=====================================output===================================== =====================================output=====================================
{{! after }} {{! after }}
<span> <span>
foo<span> foo
<span>
bar bar
</span> </span>
</span> </span>
{{! before }} {{! before }}
<span> <span>
<span> <span>
@ -47,17 +49,21 @@ printWidth: 40
</span> </span>
foo foo
</span> </span>
{{! within }} {{! within }}
<span> <span>
foo<span> foo
<span>
bar bar
</span> </span>
</span> </span>
{{! break components }} {{! break components }}
<div> <div>
<SuperSelect> <SuperSelect>
<p> <p>
foo<span> foo
<span>
bar bar bar bar bar bar
</span> </span>
</p> </p>
@ -73,10 +79,13 @@ printWidth: 40
nope nope
</h2> </h2>
</div> </div>
<div> <div>
hello<strong> hello
<strong>
hi hi
</strong> </strong>
<foo> <foo>
sdkflsdfjk sdkflsdfjk
</foo> </foo>
@ -110,31 +119,27 @@ hey
=====================================output===================================== =====================================output=====================================
<p> <p>
Hi {{firstName}} {{lastName Hi {{firstName}} {{lastName
}}, welcome! }} , welcome!
</p> </p>
{{#component propA}} {{#component propA}}
for{{propB}}do{{propC}}f for {{propB}} do {{propC}} f
{{/component}} {{/component}}
{{#component propA}} {{#component propA}}
for for {{propB}}
{{propB}}
<span> <span>
name name
</span> </span>
do do {{propC}} f
{{propC}}
f
{{/component}} {{/component}}
{{propA}} {{propA}} {{propB}}
{{propB}} {{propC}}{{propD}}
{{propC}}
{{propD}}
<span> <span>
{{propE}} {{propF}} {{propE}} {{propF}}
</span> </span>
<span> <span>
{{propG}}{{propH}} {{propG}}{{propH}}
</span> </span>
hey hey
================================================================================ ================================================================================
`; `;
@ -294,22 +299,22 @@ conubia nostra, per inceptos himenaeos. Donec in ornare velit.</p>
vestibulum facilisis in porta turpis. Ut faucibus lectus sit amet urna consectetur dignissim. vestibulum facilisis in porta turpis. Ut faucibus lectus sit amet urna consectetur dignissim.
Sam vitae neque quis ex dapibus faucibus at sed ligula. Nulla sit amet aliquet nibh. Sam vitae neque quis ex dapibus faucibus at sed ligula. Nulla sit amet aliquet nibh.
Vestibulum at congue mi. Suspendisse vitae odio vitae massa hendrerit mattis sed eget dui. Vestibulum at congue mi. Suspendisse vitae odio vitae massa hendrerit mattis sed eget dui.
Sed eu scelerisque neque. Donec<b Sed eu scelerisque neque. Donec
> <b>
maximus maximus
</b> </b>
rhoncus pellentesque. Aenean purus turpis, vehicula rhoncus pellentesque. Aenean purus turpis, vehicula
euismod ante vel, ultricies eleifend dui. Class aptent taciti sociosqu ad litora torquent per euismod ante vel, ultricies eleifend dui. Class aptent taciti sociosqu ad litora torquent per
conubia nostra, per inceptos himenaeos. Donec in ornare velit. conubia nostra, per inceptos himenaeos. Donec in ornare velit.
</p> </p>
<p> <p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce cursus massa vel augue Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce cursus massa vel augue
vestibulum facilisis in porta turpis. Ut faucibus lectus sit amet urna consectetur dignissim. vestibulum facilisis in porta turpis. Ut faucibus lectus sit amet urna consectetur dignissim.
Sam vitae neque quis ex dapibus faucibus at sed ligula. Nulla sit amet aliquet nibh. Sam vitae neque quis ex dapibus faucibus at sed ligula. Nulla sit amet aliquet nibh.
Vestibulum at congue mi. Suspendisse vitae odio vitae massa hendrerit mattis sed eget dui. Vestibulum at congue mi. Suspendisse vitae odio vitae massa hendrerit mattis sed eget dui.
Sed eu scelerisque neque. Donec<a Sed eu scelerisque neque. Donec
href="#" <a href="#">
>
<b> <b>
maximus maximus
</b> </b>
@ -365,10 +370,10 @@ printWidth: 40
This is your name: {{name}}. This is your name: {{name}}.
</span> </span>
<span> <span>
This is your name: {{name}}(employee) This is your name: {{name}} (employee)
</span> </span>
<span> <span>
This is your name: {{name}}({{role}}) This is your name: {{name}} ({{role}})
</span> </span>
================================================================================ ================================================================================
`; `;
@ -410,6 +415,7 @@ printWidth: 40
<span> <span>
123 123
</span> </span>
<div> <div>
123 123
</div> </div>
@ -468,40 +474,44 @@ printWidth: 40
</tr> </tr>
</thead> </thead>
</table> </table>
<table>
<thead>
<tr>
<th>
A
</th>
<th>
B
</th>
<th>
C
</th>
</tr>
</thead>
</table>
<table>
<thead>
<tr>
<th>
A
</th>
<th>
B
</th>
<th>
C
</th>
</tr>
</thead>
</table>
<table>
<thead>
<tr>
<table>
<thead>
<tr>
<th>
A
</th>
<th>
B
</th>
<th>
C
</th>
</tr>
</thead>
</table>
<table>
<thead>
<tr>
<th>
A
</th>
<th>
B
</th>
<th>
C
</th>
</tr>
</thead>
</table>
<table>
<thead>
<tr>
</tr> </tr>
</thead> </thead>
</table> </table>