vuejs / eslint-plugin-vue

Official ESLint plugin for Vue.js
https://eslint.vuejs.org/
MIT License
4.47k stars 667 forks source link

Add option to ignore comments in `vue/multiline-html-element-content-newline` #2581

Open dsl101 opened 4 weeks ago

dsl101 commented 4 weeks ago

Fixes #2179

I finally got around to looking at a PR. It seems deceptively simple, so not sure if it broke something elsewhere, but no other tests seemed affected.

dsl101 commented 4 weeks ago

If the approach is OK, I'll add to the docs

FloEdelmann commented 4 weeks ago

Looks good to me :slightly_smiling_face: Please go ahead and adjust the docs now :wink:

FloEdelmann commented 4 weeks ago

And could you also add the same option to vue/singleline-html-element-content-newline as well please?

dsl101 commented 4 weeks ago

And could you also add the same option to vue/singleline-html-element-content-newline as well please?

I'm unsure how to do this, as a straight copy / paste of the changes into that rule doesn't quite work the same. For example, with ignoreComments: true this test failes:

  valid: [{
    code: `
      <template>
        <div attr> <!-- comment --> </div>
      </template>`,
    options: [
      {
        ignoreComments: true
      }
    ]
  }]

with these errors:

  1) singleLineRule
       valid

      <template>
        <div attr> <!-- comment --> </div>
      </template>:

      AssertionError [ERR_ASSERTION]: Should have no errors but had 2: [
  {
    ruleId: 'singleLineRule',
    severity: 1,
    message: 'Expected 1 line break after opening tag (`<div>`), but no line breaks found.',
    line: 3,
    column: 19,
    nodeType: 'HTMLTagClose',
    messageId: 'unexpectedAfterClosingBracket',
    endLine: 3,
    endColumn: 37,
    fix: { range: [Array], text: '\n' }
  },
  {
    ruleId: 'singleLineRule',
    severity: 1,
    message: 'Expected 1 line break before closing tag (`</div>`), but no line breaks found.',
    line: 3,
    column: 19,
    nodeType: 'HTMLEndTagOpen',
    messageId: 'unexpectedBeforeOpeningBracket',
    endLine: 3,
    endColumn: 37,
    fix: { range: [Array], text: '\n' }
  }
]

But if I remove the whitespace around the comment:

  valid: [{
    code: `
      <template>
        <div attr><!-- comment --></div>
      </template>`,
    options: [
      {
        ignoreComments: true
      }
    ]
  }]

the test passes fine. I didn't see this issue in the multiline rule.

In this section of the rule code here:

        if (
          ignoreWhenEmpty &&
          elem.children.length === 0 &&
          template.getFirstTokensBetween(
            elem.startTag,
            elem.endTag,
            getTokenOption
          ).length === 0
        ) {
          return
        }

I'm not sure why it's required to test elem.children.length === 0 and getFirstTokensBetween().length === 0—indeed, commenting that line out:

        if (
          ignoreWhenEmpty &&
          // elem.children.length === 0 &&
          template.getFirstTokensBetween(
            elem.startTag,
            elem.endTag,
            getTokenOption
          ).length === 0
        ) {
          return
        }

then makes this valid:

      <template>
        <div attr> <!-- comment --> </div>
      </template>`

but still reports errors for this:

      <template>
        <div attr> content <!-- comment --> </div>
      </template>`
FloEdelmann commented 4 weeks ago

I'm not sure why it's required to test elem.children.length === 0 and getFirstTokensBetween().length === 0

Probably it is indeed not needed, seems like both were added at the same time in #684. I guess if the other tests are passing, then removing the elem.children.length check should be fine.

dsl101 commented 4 weeks ago

Ah, this is a bit more complicated than I thought. Without my proposed changes, the default settings for singleline-html-element-content-newline give these test results:

  1. <div></div> → OK
  2. <div> </div> → OK
  3. <div attr></div> → OK
  4. <div attr> </div> → Fail

I'm not sure if the behaviour here is really consistent—shouldn't 2 and 4 give the same result? Because the setting is ignoreWhenNoAttributes and defaults to true, I can't see a way to configure that case 4 passes the test. Is the only option here to just disable the singleline-html-element-content-newline rule altogether?

It complicates my use case, as it's very common to put white space around comments, but then that white space counts as 'content':

<div attr><!-- comment --></div> → OK <div attr> <!-- comment --> </div> → Fail

But I think that's OK, and is consistent with the existing rules / tests. I'll push an update with documentation for you to see.

FloEdelmann commented 4 weeks ago

It seems that the simple fix is also not working correctly for multiline-html-element-content-newline, see https://deploy-preview-2581--eslint-plugin-vue.netlify.app/rules/multiline-html-element-content-newline.html#ignorecomments-true:

<template>
  <!-- should be good, but actually is reported because the div is now 2 line breaks below the template -->
  <div class="red">  <!-- no error is reported here -->
    content
  </div>
</template>

So apparently a more elaborate logic is needed after all, probably that logic can then also be used for the singleline-html-element-content-newline rule.