Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AngularJS HTML formatting incorrect #5449

Closed
MikaelEdebro opened this issue Nov 12, 2018 · 11 comments
Closed

AngularJS HTML formatting incorrect #5449

MikaelEdebro opened this issue Nov 12, 2018 · 11 comments
Labels
lang:angular Issues affecting Angular template (not general JS/TS issues used for Angular) lang:html Issues affecting HTML (and SVG but not JSX) lang:vue Issues affecting Vue locked-due-to-inactivity Please open a new issue and fill out the template instead of commenting. status:needs discussion Issues needing discussion and a decision to be made before action can be taken

Comments

@MikaelEdebro
Copy link

MikaelEdebro commented Nov 12, 2018

I'm testing out the new HTML formatting on a AngularJS project at work. But unfortunately it messes up the code. I'm running the latest version of the VSCode plugin.

I'll attach a GIF and the problematic markup for testing:
Imgur

Code:

<div class="row">
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsSendReportName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).reportsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsSendReportName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).reportsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{"statisticsTimeFor" | i18n}} {{"statisticsLatest" | i18n}} {{"statisticsSendReportName" | i18n}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).latestReportTime}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsEventName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).eventsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsEventName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).eventsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsPollName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).pollsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsPollName'|i18n}}  {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).pollsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsPollStatusName' | i18n}} <span class="glyphicon glyphicon-info-sign" uib-tooltip="{{'statisticsPollStatusTooltip' | i18n }}" tooltip-placement="right"></span></b>
        <p>{{dataStatisticsMap.get(timeUnit).pollIntervalStatusOk ? 'yes' : 'no' | i18n }}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsValidationErrorName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).validationErrorsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsValidationErrorName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).validationErrorsCount}}</p>
    </div>
</div>

When running the code on prettier.io > Try it out, I'm getting:

SyntaxError: Unexpected token (3:40)
  1 | <div class="row">
  2 |     <div class="col-xs-4 col-md-2">
> 3 |         <b>{{'statisticsSendReportName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
    |                                        ^
  4 |         <p>{{dataStatisticsMap.get(timeUnit).reportsCount}}</p>
  5 |     </div>
  6 |     <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
@ikatyang
Copy link
Member

There's a Show options on the bottom left, you have to specify the --parser angular.

playground

Prettier 1.15.2
Playground link

--parser angular

Input:

<div class="row">
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsSendReportName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).reportsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsSendReportName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).reportsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{"statisticsTimeFor" | i18n}} {{"statisticsLatest" | i18n}} {{"statisticsSendReportName" | i18n}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).latestReportTime}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsEventName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).eventsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsEventName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).eventsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsPollName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).pollsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsPollName'|i18n}}  {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).pollsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsPollStatusName' | i18n}} <span class="glyphicon glyphicon-info-sign" uib-tooltip="{{'statisticsPollStatusTooltip' | i18n }}" tooltip-placement="right"></span></b>
        <p>{{dataStatisticsMap.get(timeUnit).pollIntervalStatusOk ? 'yes' : 'no' | i18n }}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsValidationErrorName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).validationErrorsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsValidationErrorName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).validationErrorsCount}}</p>
    </div>
</div>

Output:

<div class="row">
  <div class="col-xs-4 col-md-2">
    <b
      >{{ "statisticsSendReportName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnit }}</b
    >
    <p>{{ dataStatisticsMap.get(timeUnit).reportsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b
      >{{ "statisticsSendReportName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnitSecondary }}</b
    >
    <p>{{ dataStatisticsMap.get(timeUnitSecondary).reportsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b
      >{{ "statisticsTimeFor" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ "statisticsSendReportName" | i18n }}</b
    >
    <p>{{ dataStatisticsMap.get(timeUnit).latestReportTime }}</p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b
      >{{ "statisticsEventName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnit }}</b
    >
    <p>{{ dataStatisticsMap.get(timeUnit).eventsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b
      >{{ "statisticsEventName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnitSecondary }}</b
    >
    <p>{{ dataStatisticsMap.get(timeUnitSecondary).eventsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b
      >{{ "statisticsPollName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnit }}</b
    >
    <p>{{ dataStatisticsMap.get(timeUnit).pollsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b
      >{{ "statisticsPollName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnitSecondary }}</b
    >
    <p>{{ dataStatisticsMap.get(timeUnitSecondary).pollsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b
      >{{ "statisticsPollStatusName" | i18n }}
      <span
        class="glyphicon glyphicon-info-sign"
        uib-tooltip="{{'statisticsPollStatusTooltip' | i18n }}"
        tooltip-placement="right"
      ></span
    ></b>
    <p>
      {{
        dataStatisticsMap.get(timeUnit).pollIntervalStatusOk
          ? "yes"
          : ("no" | i18n)
      }}
    </p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b
      >{{ "statisticsValidationErrorName" | i18n }}
      {{ "statisticsLatest" | i18n }} {{ timeUnit }}</b
    >
    <p>{{ dataStatisticsMap.get(timeUnit).validationErrorsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b
      >{{ "statisticsValidationErrorName" | i18n }}
      {{ "statisticsLatest" | i18n }} {{ timeUnitSecondary }}</b
    >
    <p>{{ dataStatisticsMap.get(timeUnitSecondary).validationErrorsCount }}</p>
  </div>
</div>

But unfortunately it messes up the code.

What did you mean "mess up"? what's your expected behavior?

@ikatyang ikatyang added the status:awaiting response Issues that require answers to questions from maintainers before action can be taken label Nov 12, 2018
@MikaelEdebro
Copy link
Author

MikaelEdebro commented Nov 13, 2018

Ok great! When using parser = angular, the playground got the same result as VS Code plugin.

But what I mean by "mess up". This is the way it formats the <b> tags:

<b
      >{{ "statisticsEventName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnit }}</b
    >

Link to the Playground

@no-response no-response bot removed the status:awaiting response Issues that require answers to questions from maintainers before action can be taken label Nov 13, 2018
@ikatyang
Copy link
Member

What's your expected output?

@ikatyang ikatyang added the status:awaiting response Issues that require answers to questions from maintainers before action can be taken label Nov 13, 2018
@MikaelEdebro
Copy link
Author

MikaelEdebro commented Nov 13, 2018

I would expect it not to break the html tags in multiple lines. That only makes sense if there are multiple attributes?!?

I would expect something like this:

<div class="col-xs-4 col-md-2">
    <b>
        {{"statisticsTimeFor" | i18n}} 
        {{"statisticsLatest" | i18n}} 
        {{"statisticsSendReportName" | i18n}}
    </b>
    <p>{{dataStatisticsMap.get(timeUnit).latestReportTime}}</p>
</div>

Hope I'm not coming off too critical. I really think Prettier is an awesome tool, and it's great that you have included HTML in it's arsenal. But in this particular case, the formatting seems a bit off. :)

@no-response no-response bot removed the status:awaiting response Issues that require answers to questions from maintainers before action can be taken label Nov 13, 2018
@ikatyang
Copy link
Member

You may want to take a look at whitespace-sensitive formatting, that's why we cannot add whitespaces there as it'll break your code, but if you don't care about those whitespaces, just use --html-whitespace-sensitivity ignore.

(There're actually some ignorable whitespaces we didn't take into account, which is tracked in #5439.)

playground with --html-whitespace-sensitivity ignore

Prettier 1.15.2
Playground link

--html-whitespace-sensitivity ignore
--parser angular

Input:

<div class="row">
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsSendReportName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).reportsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsSendReportName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).reportsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{"statisticsTimeFor" | i18n}} {{"statisticsLatest" | i18n}} {{"statisticsSendReportName" | i18n}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).latestReportTime}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsEventName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).eventsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsEventName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).eventsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsPollName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).pollsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsPollName'|i18n}}  {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).pollsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsPollStatusName' | i18n}} <span class="glyphicon glyphicon-info-sign" uib-tooltip="{{'statisticsPollStatusTooltip' | i18n }}" tooltip-placement="right"></span></b>
        <p>{{dataStatisticsMap.get(timeUnit).pollIntervalStatusOk ? 'yes' : 'no' | i18n }}</p>
    </div>
    <div class="col-xs-4 col-md-2">
        <b>{{'statisticsValidationErrorName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnit}}</b>
        <p>{{dataStatisticsMap.get(timeUnit).validationErrorsCount}}</p>
    </div>
    <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
        <b>{{'statisticsValidationErrorName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
        <p>{{dataStatisticsMap.get(timeUnitSecondary).validationErrorsCount}}</p>
    </div>
</div>

Output:

<div class="row">
  <div class="col-xs-4 col-md-2">
    <b>
      {{ "statisticsSendReportName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnit }}
    </b>
    <p>{{ dataStatisticsMap.get(timeUnit).reportsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b>
      {{ "statisticsSendReportName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnitSecondary }}
    </b>
    <p>{{ dataStatisticsMap.get(timeUnitSecondary).reportsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b>
      {{ "statisticsTimeFor" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ "statisticsSendReportName" | i18n }}
    </b>
    <p>{{ dataStatisticsMap.get(timeUnit).latestReportTime }}</p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b>
      {{ "statisticsEventName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnit }}
    </b>
    <p>{{ dataStatisticsMap.get(timeUnit).eventsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b>
      {{ "statisticsEventName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnitSecondary }}
    </b>
    <p>{{ dataStatisticsMap.get(timeUnitSecondary).eventsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b>
      {{ "statisticsPollName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnit }}
    </b>
    <p>{{ dataStatisticsMap.get(timeUnit).pollsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b>
      {{ "statisticsPollName" | i18n }} {{ "statisticsLatest" | i18n }}
      {{ timeUnitSecondary }}
    </b>
    <p>{{ dataStatisticsMap.get(timeUnitSecondary).pollsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b>
      {{ "statisticsPollStatusName" | i18n }}
      <span
        class="glyphicon glyphicon-info-sign"
        uib-tooltip="{{'statisticsPollStatusTooltip' | i18n }}"
        tooltip-placement="right"
      ></span>
    </b>
    <p>
      {{
        dataStatisticsMap.get(timeUnit).pollIntervalStatusOk
          ? "yes"
          : ("no" | i18n)
      }}
    </p>
  </div>
  <div class="col-xs-4 col-md-2">
    <b>
      {{ "statisticsValidationErrorName" | i18n }}
      {{ "statisticsLatest" | i18n }} {{ timeUnit }}
    </b>
    <p>{{ dataStatisticsMap.get(timeUnit).validationErrorsCount }}</p>
  </div>
  <div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b>
      {{ "statisticsValidationErrorName" | i18n }}
      {{ "statisticsLatest" | i18n }} {{ timeUnitSecondary }}
    </b>
    <p>{{ dataStatisticsMap.get(timeUnitSecondary).validationErrorsCount }}</p>
  </div>
</div>

@ikatyang ikatyang added the status:awaiting response Issues that require answers to questions from maintainers before action can be taken label Nov 13, 2018
@JLHwung
Copy link
Contributor

JLHwung commented Nov 14, 2018

The angular parser works good with AngularJS templates, I suggest the issue be closed.

BTW should we document on https://prettier.io/blog/2018/11/07/1.15.0.html that AngularJS template should be parsed with angular parser? One should probably specify --parser angular for *.html given Angular JS template have no naming convention.

@ikatyang
Copy link
Member

I did mention it in the blog post, the issue here is probably same as #5462 (comment), where Angular did strip whitespaces (insensitive) in some cases.

Unrelated: @JLHwung Would you mind to take look at #5368 (the regression there seems caused by upgrading cjk-regex from v1 to v2)? I did a quick fix in #5402 but I'm not quite sure if it's the proper fix given that I'm not too familiar with unicode. Thanks!

@thorn0
Copy link
Member

thorn0 commented Nov 14, 2018

Unlike Angular, AngularJS doesn't strip any white spaces.

@JLHwung There is at least one incompatibility: #5466

@JLHwung
Copy link
Contributor

JLHwung commented Nov 14, 2018

I did mention it in the blog post, the issue here is probably same as #5462 (comment), where Angular did strip whitespaces (insensitive) in some cases.

By stressing AngularJS versus Angular, I mean they are different framework, though they have similar name and Angular evolves from AngularJS. As it is shown on #5466, they have a slight different grammar.

@ikatyang On the fix in #5402, you did a great job! I have reviewed the code change and do find some rare cases and it should be addressed in #5480.

@MikaelEdebro
Copy link
Author

MikaelEdebro commented Nov 15, 2018

I don't know anything about the implementation details, and the 1000 issues that you probably have to face to support every edge case.

But as a user, I would rather prefer that print-width is disregarded if there are uncertanties about how to handle whitespace (rather than breaking up the HTML-elements in multiple lines). In my opinion print-width is not as important for readability in HTML as in JS.

For example, that this:

<div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b>{{'statisticsSendReportName'|i18n}} {{"statisticsLatest" | i18n}} {{timeUnitSecondary}}</b>
    <p>{{dataStatisticsMap.get(timeUnitSecondary).reportsCount}}</p>
</div>

Would become:

<div class="col-xs-4 col-md-2" ng-show="overviewSelected">
    <b>
        {{'statisticsSendReportName' | i18n}} {{'statisticsLatest' | i18n}} {{timeUnitSecondary}}
    </b>
    <p>{{dataStatisticsMap.get(timeUnitSecondary).reportsCount}}</p>
</div>

@no-response no-response bot removed the status:awaiting response Issues that require answers to questions from maintainers before action can be taken label Nov 15, 2018
@alexander-akait alexander-akait added status:needs discussion Issues needing discussion and a decision to be made before action can be taken lang:angular Issues affecting Angular template (not general JS/TS issues used for Angular) lang:html Issues affecting HTML (and SVG but not JSX) lang:vue Issues affecting Vue labels Aug 7, 2019
@thorn0
Copy link
Member

thorn0 commented May 6, 2020

I don't see anything that needs discussion or fixing in this issue.
--html-whitespace-sensitivity ignore does what the OP wanted.

@thorn0 thorn0 closed this as completed May 6, 2020
@github-actions github-actions bot added the locked-due-to-inactivity Please open a new issue and fill out the template instead of commenting. label Aug 5, 2020
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
lang:angular Issues affecting Angular template (not general JS/TS issues used for Angular) lang:html Issues affecting HTML (and SVG but not JSX) lang:vue Issues affecting Vue locked-due-to-inactivity Please open a new issue and fill out the template instead of commenting. status:needs discussion Issues needing discussion and a decision to be made before action can be taken
Projects
None yet
Development

No branches or pull requests

5 participants