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
[#6033]: https://github.com/prettier/prettier/pull/6033
[#6186]: https://github.com/prettier/prettier/pull/6186
@ -1087,3 +1130,4 @@ class A {
[@squidfunk]: https://github.com/squidfunk
[@vjeux]: https://github.com/vjeux
[@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);
if (isWhitespace && isLastNodeInMultiNodeList) {
return concat([print(childPath, options, print)]);
} else if (
isFirstNode ||
isPreviousNodeOfSomeType(childPath, [
"ElementNode",
"CommentStatement",
"MustacheCommentStatement",
"BlockStatement"
])
) {
return print(childPath, options, print);
} else if (isFirstNode) {
return concat([softline, print(childPath, options, print)]);
}
return concat([print(childPath, options, print)]);
return print(childPath, options, print);
}, "children")
);
}
@ -72,9 +64,7 @@ function print(path, options, print) {
case "Block":
case "Program":
case "Template": {
return group(
join(softline, path.map(print, "body").filter(text => text !== ""))
);
return group(concat(path.map(print, "body").filter(text => text !== "")));
}
case "ElementNode": {
const tagFirstChar = n.tag[0];
@ -82,8 +72,14 @@ function print(path, options, print) {
const isGlimmerComponent =
tagFirstChar.toUpperCase() === tagFirstChar || isLocal;
const hasChildren = n.children.length > 0;
const hasNonWhitespaceChildren = n.children.some(
n => !isWhitespaceNode(n)
);
const isVoid =
(isGlimmerComponent && !hasChildren) || voidTags.indexOf(n.tag) !== -1;
(isGlimmerComponent && (!hasChildren || !hasNonWhitespaceChildren)) ||
voidTags.indexOf(n.tag) !== -1;
const closeTagForNoBreak = isVoid ? concat([" />", softline]) : ">";
const closeTagForBreak = isVoid ? "/>" : ">";
const getParams = (path, print) =>
@ -100,6 +96,8 @@ function print(path, options, print) {
])
);
const nextNode = getNextNode(path);
return concat([
group(
concat([
@ -111,13 +109,18 @@ function print(path, options, print) {
ifBreak(closeTagForBreak, closeTagForNoBreak)
])
),
group(
concat([
indent(printChildren(path, options, print)),
ifBreak(hasChildren ? hardline : "", ""),
!isVoid ? concat(["</", n.tag, ">"]) : ""
])
)
!isVoid
? group(
concat([
hasNonWhitespaceChildren
? indent(printChildren(path, options, print))
: "",
ifBreak(hasChildren ? hardline : "", ""),
concat(["</", n.tag, ">"])
])
)
: "",
nextNode && nextNode.type === "ElementNode" ? hardline : ""
]);
}
case "BlockStatement": {
@ -156,6 +159,7 @@ function print(path, options, print) {
const hasNonWhitespaceChildren = n.program.body.some(
n => !isWhitespaceNode(n)
);
return concat([
printOpenBlock(path, print),
group(
@ -196,7 +200,9 @@ function print(path, options, print) {
return concat([n.name]);
}
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]);
}
case "ConcatStatement": {
@ -222,25 +228,54 @@ function print(path, options, print) {
return concat([n.key, "=", path.call(print, "value")]);
}
case "TextNode": {
const maxLineBreaksToPreserve = 2;
const isFirstElement = !getPreviousNode(path);
const isLastElement = !getNextNode(path);
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 (
(isFirstElement || isLastElement) &&
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 trailingSpace = "";
if (isNextNodeOfType(path, "MustacheStatement")) {
trailingSpace = " ";
}
// preserve a space inside of an attribute node where whitespace present, 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;
if (inAttrNode) {
const parentNode = path.getParentNode(0);
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)
.replace(/\s+$/, trailingSpace);
return concat(
[
...generateHardlines(leadingLineBreaksCount, maxLineBreaksToPreserve),
n.chars
.replace(/^[\s ]+/g, leadingSpace)
.replace(/[\s ]+$/, trailingSpace),
...generateHardlines(trailingLineBreaksCount, maxLineBreaksToPreserve)
].filter(Boolean)
);
}
case "MustacheCommentStatement": {
const dashes = n.value.indexOf("}}") > -1 ? "--" : "";
@ -405,7 +471,7 @@ function getPreviousNode(path) {
const node = path.getValue();
const parentNode = path.getParentNode(0);
const children = parentNode.children;
const children = parentNode.children || parentNode.body;
if (children) {
const nodeIndex = children.indexOf(node);
if (nodeIndex > 0) {
@ -419,7 +485,7 @@ function getNextNode(path) {
const node = path.getValue();
const parentNode = path.getParentNode(0);
const children = parentNode.children;
const children = parentNode.children || parentNode.body;
if (children) {
const nodeIndex = children.indexOf(node);
if (nodeIndex < children.length) {
@ -445,6 +511,7 @@ function isNextNodeOfType(path, type) {
function clean(ast, newObj) {
delete newObj.loc;
delete newObj.selfClosing;
// (Glimmer/HTML) ignore TextNode whitespace
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 = {
print,
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>
</script>
<div class="{{hello}} {{world}}"></div>
================================================================================
`;
@ -61,6 +62,7 @@ singleQuote: true
</div>
</div>
</script>
<div class="{{hello}} {{world}}"></div>
================================================================================
`;
@ -99,28 +101,33 @@ printWidth: 80
=====================================output=====================================
<UserGreeting @name="Ricardo" @greeting="Olá" />
{{@greeting}}
,
{{@name}}
!
{{@greeting}}, {{@name}}!
<div>
<UserGreeting
@aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}}
/>
</div>
<Form as |f|>
<f.input @title="hello" />
<f.input>
hello
</f.input>
</Form>
<this.label @title="hello" />
<button onclick={{action next}}>
Next
</button>
<button disabled class="disabled"></button>
<button disabled="disabled" class="disabled"></button>
<img alt="" />
<div ...attributes>
Hello
</div>
@ -162,28 +169,33 @@ singleQuote: true
=====================================output=====================================
<UserGreeting @name='Ricardo' @greeting='Olá' />
{{@greeting}}
,
{{@name}}
!
{{@greeting}}, {{@name}}!
<div>
<UserGreeting
@aVeryLongArgumentNameThatIsStillGoing={{@alsoAVeryLongArgument}}
/>
</div>
<Form as |f|>
<f.input @title='hello' />
<f.input>
hello
</f.input>
</Form>
<this.label @title='hello' />
<button onclick={{action next}}>
Next
</button>
<button disabled class='disabled'></button>
<button disabled='disabled' class='disabled'></button>
<img alt='' />
<div ...attributes>
Hello
</div>
@ -264,6 +276,7 @@ printWidth: 80
<h2>
By {{author.name}}
</h2>
<div class="body">
{{body}}
</div>
@ -295,6 +308,7 @@ singleQuote: true
<h2>
By {{author.name}}
</h2>
<div class='body'>
{{body}}
</div>

View File

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

View File

@ -30,11 +30,13 @@ printWidth: 80
{{#if @foo}}
Foo
{{/if}}
{{! Bar }}
{{#if @bar}}
Bar
{{/if}}
</div>
<div class="entry">
{{! This comment 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}}">
Hello
</div>
<div
class="hello
{{if goodbye true}}
@ -44,7 +45,9 @@ printWidth: 80
>
Hello
</div>
<a href="/{{url}}/{{url}}"></a>
<div class="class-a{{myClass}}"></div>
<div class="class-b {{myClass}}"></div>
<div class="{{myClass}}class-c"></div>
@ -89,6 +92,7 @@ singleQuote: true
<div class="hello {{if goodbye true}}">
Hello
</div>
<div
class="hello
{{if goodbye true}}
@ -103,7 +107,9 @@ singleQuote: true
>
Hello
</div>
<a href="/{{url}}/{{url}}"></a>
<div class="class-a{{myClass}}"></div>
<div class="class-b {{myClass}}"></div>
<div class="{{myClass}}class-c"></div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,10 +36,12 @@ printWidth: 40
=====================================output=====================================
{{! after }}
<span>
foo<span>
foo
<span>
bar
</span>
</span>
{{! before }}
<span>
<span>
@ -47,17 +49,21 @@ printWidth: 40
</span>
foo
</span>
{{! within }}
<span>
foo<span>
foo
<span>
bar
</span>
</span>
{{! break components }}
<div>
<SuperSelect>
<p>
foo<span>
foo
<span>
bar bar bar
</span>
</p>
@ -73,10 +79,13 @@ printWidth: 40
nope
</h2>
</div>
<div>
hello<strong>
hello
<strong>
hi
</strong>
<foo>
sdkflsdfjk
</foo>
@ -110,31 +119,27 @@ hey
=====================================output=====================================
<p>
Hi {{firstName}} {{lastName
}}, welcome!
}} , welcome!
</p>
{{#component propA}}
for{{propB}}do{{propC}}f
for {{propB}} do {{propC}} f
{{/component}}
{{#component propA}}
for
{{propB}}
for {{propB}}
<span>
name
</span>
do
{{propC}}
f
do {{propC}} f
{{/component}}
{{propA}}
{{propB}}
{{propC}}
{{propD}}
{{propA}} {{propB}}
{{propC}}{{propD}}
<span>
{{propE}} {{propF}}
</span>
<span>
{{propG}}{{propH}}
</span>
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.
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.
Sed eu scelerisque neque. Donec<b
>
Sed eu scelerisque neque. Donec
<b>
maximus
</b>
rhoncus pellentesque. Aenean purus turpis, vehicula
euismod ante vel, ultricies eleifend dui. Class aptent taciti sociosqu ad litora torquent per
conubia nostra, per inceptos himenaeos. Donec in ornare velit.
</p>
<p>
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.
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.
Sed eu scelerisque neque. Donec<a
href="#"
>
Sed eu scelerisque neque. Donec
<a href="#">
<b>
maximus
</b>
@ -365,10 +370,10 @@ printWidth: 40
This is your name: {{name}}.
</span>
<span>
This is your name: {{name}}(employee)
This is your name: {{name}} (employee)
</span>
<span>
This is your name: {{name}}({{role}})
This is your name: {{name}} ({{role}})
</span>
================================================================================
`;
@ -410,6 +415,7 @@ printWidth: 40
<span>
123
</span>
<div>
123
</div>
@ -468,40 +474,44 @@ printWidth: 40
</tr>
</thead>
</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>
</thead>
</table>