js-beautify icon indicating copy to clipboard operation
js-beautify copied to clipboard

HTML formatter breaks layout by introducing newlines

Open lgarron opened this issue 2 years ago • 8 comments

Moved here from https://github.com/microsoft/vscode/issues/144042

Description

The HTML formatter breaks the layout of the page.

Input

The code looked like this before beautification:

<span>
  <span>
    <span>1:02</span
    ><time-dot>.</time-dot
    ><time-decimals>27</time-decimals>
  </span>
</span>

Expected Output

The code should have looked like this after beautification:

<!-- no change? -->
<span>
  <span>
    <span>1:02</span
    ><time-dot>.</time-dot
    ><time-decimals>27</time-decimals>
  </span>
</span>

Actual Output

The code actually looked like this after beautification:

<span>
  <span>
    <span>1:02</span>
    <time-dot>.</time-dot>
    <time-decimals>27</time-decimals>
  </span>
</span>

This introduces newlines (and spaces) before and after the <time-dot> element, which adds visual space between the elements on the page that was not there before:

Screen Shot 2022-02-27 at 14 40 15

Steps to Reproduce

Paste into https://beautifier.io/ or format in VSCode.

Environment

OS: N/A

Settings

Default?

lgarron avatar Feb 28 '22 18:02 lgarron

FYI: The bug template says:

  • Do not include screenshots! This library is a text processor, we need text inputs and outputs for debugging and fixing issues.

I assume this means "do not submit screenshots without submitting associated text examples", not "screenshots are forbidden, even if they illustrate the text examples". Apologies if that's not the case.

lgarron avatar Feb 28 '22 18:02 lgarron

@lgarron

This is good bug. Took me looking twice at the image, but that made it clear what the problem is. Thanks!

It appears that you want <time-dot> and <time-decimals> to be treated as "inline" elements.

However, the beautifier doesn't do the end braces the way you said in your expected output. Once you made the elements "inline", the expected output would be:

<span>
  <span>
    <span>1:02</span><time-dot>.</time-dot><time-decimals>27</time-decimals>
  </span>
</span>

Question: <time-dot> and <time-decimals> are not valid html elements. Where are you getting them?

bitwiseman avatar Mar 04 '22 17:03 bitwiseman

It appears that you want <time-dot> and <time-decimals> to be treated as "inline" elements.

Correct, that is how they are treated by default.

Question: <time-dot> and <time-decimals> are not valid html elements. Where are you getting them?

Any tag with a hyphen is a valid custom element name. They can be defined in JS, but they can also be used in the DOM (and styled) before being defined.

Would it be feasible to conservatively treat every hyphenated tag as inline?

lgarron avatar Mar 04 '22 22:03 lgarron

poke

This is still really frustrating. It completely breaks the layout of some pages in VSCode out of the box, which requires a moment of "what happened?" followed by turning off HTML formatting completely (therefore missing out on the benefits). 🥺

lgarron avatar Jun 27 '22 19:06 lgarron

@lgarron can you assign this issue to me

EktaEngineer avatar Sep 21 '22 17:09 EktaEngineer

@lgarron can you assign this issue to me

That would be up to @bitwiseman.

In any case, I would still be glad to see this addressed.

lgarron avatar Sep 21 '22 18:09 lgarron

This might be a potential solution: https://github.com/lgarron/js-beautify/commit/cef7e86cb76659067929af2ac2fa89b46777aaa3

commit cef7e86cb76659067929af2ac2fa89b46777aaa3
Author: Lucas Garron <[email protected]>
Date:   Wed Sep 21 11:06:57 2022 -0700

    Treat all custom elements as inline elements.
    
    Addresses https://github.com/beautify-web/js-beautify/issues/1989

diff --git a/js/src/html/beautifier.js b/js/src/html/beautifier.js
index 942d8318..3fa09194 100644
--- a/js/src/html/beautifier.js
+++ b/js/src/html/beautifier.js
@@ -658,7 +658,7 @@ Beautifier.prototype._get_tag_open_token = function(raw_token) { //function to g
 
   parser_token.is_unformatted = !parser_token.tag_complete && in_array(parser_token.tag_check, this._options.unformatted);
   parser_token.is_content_unformatted = !parser_token.is_empty_element && in_array(parser_token.tag_check, this._options.content_unformatted);
-  parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || parser_token.tag_start_char === '{';
+  parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || parser_token.tag_name.includes("-") || parser_token.tag_start_char === "{";
 
   return parser_token;
 };

lgarron avatar Sep 21 '22 18:09 lgarron

@bitwiseman can you assign this issue to me

EktaEngineer avatar Sep 21 '22 18:09 EktaEngineer