intlify / eslint-plugin-vue-i18n

:globe_with_meridians: ESLint plugin for Vue I18n
https://eslint-plugin-vue-i18n.intlify.dev/
MIT License
130 stars 39 forks source link

SFC: Opening angle bracket in yaml value makes all rules pass #107

Closed wolfgangwalther closed 3 years ago

wolfgangwalther commented 4 years ago

When using an opening angle bracket followed by at least one character in a yaml SFC component, failures are not reported anymore. The following reports DONE No lint errors found!:

<i18n lang="yaml" locale="en">
unused: "<i"
</i18n>

<template>
  <div>
    {{ $t('missing') }}
  </div>
</template>

When changing this the value to "<" or "i", the two expected errors are thrown (error: unused 'unused' key (@intlify/vue-i18n/no-unused-keys) and error: 'missing' does not exist in 'en' (@intlify/vue-i18n/no-missing-keys))

wolfgangwalther commented 4 years ago

Note, this also works correctly again, if the value is set to e.g. "<i>test</i>" - maybe some of the closing brackets make it work again. Couldn't find out what exactly that is.

ota-meshi commented 4 years ago

Thank you for this issue.

This is the current limitation of vue-eslint-parser. If you really want to write <i, you need to write &lt;i.

The Vue compiler will parse <i inside custom blocks as you intended. However, I recommend that you write &lt;i to use tools that use other HTML parsers as well. By the way, when I tried Vue3 before, it didn't parse the <i inside a custom block well. However, it may be different now.

If you really want this plugin to support <i, you need to ask vue-eslint-parser.

wolfgangwalther commented 4 years ago

I don't want to write <i, but want proper support for #108. In it's current state no-html-messages is not usable for SFC, because under some circumstances it will just make the whole file pass instead of throwing any error.

Do you think it would be possible to at least raise an error of some sort instead of just silently passing everything in this case?

I don't know the internals of vue-eslint-parser, but you already seem to do - could you add an issue at their repo? You probably know much better than me, how to describe the problem and what vue-eslint-parser actually returns and should return.

ota-meshi commented 4 years ago

I personally think the Vue compiler that parses the <i18n>{ foo: "<i" }</i18n> as you intended is the wrong spec, so I'm not going to report this issue to vue-eslint-parser. <i18n>{ foo: "<i" }</i18n> is not correct in the HTML. I personally think that the .vue should conform to the HTML specification.

However, there's no way to know if you've written the wrong HTML using this plugin, so I'll try to find out if there is a way to report the error when I have time.

wolfgangwalther commented 4 years ago

Wait what?

It's not important whether that is correct HTML or not - the i18n block is no HTML at all. It's either JSON or YAML or whatever else. And this is absolutely correct JSON/YAML!

The vue compiler does it right.

Let me make an example that makes this more clear:

You would assume that the following is valid, correct?

<script>
export default {
  methods: {
    compare_arg (arg) {
      return 0<arg
    }
  }
}
</script>

Essentially this is exactly the same - < followed by a character in the middle of the block. Only that it's a <script> block and not a <i18n> block here. But this behaviour should be the same for custom blocks. The underlying assumption that the content of that would have to be HTML is just wrong. So while the outer structure of the SFC file is HTML, the inner structure of a custom block is not - and therefore using < is completely legal*.

So this is definitely wrong in vue-eslint-parser.

I mean I would totally be ok, if that was throwing some kind of error or something - but just ignoring everything and passing all rules renders all the SFC functionality useless. If you accidently put in a < you will not be warned about anything anymore.

As you know more about vue-eslint-parser than I do - can you give me a little guidance what it returns for this (<i18n>{ foo: "<i" }</i18n>) exactly? Does it just return a part of the block or does it throw an error or does it just return an empty block or no block at all or ...? Running out of ideas here ;) This would help me to describe the problem better, so I can open the issue myself. Thanks!!

* I do understand that it gets tricky if you try to use something like <i18n>{ foo: "</i18n>" }</i18n> - and I would not expect that to work. That's the same with using '</script>' inside a <script> tag...

ota-meshi commented 4 years ago

It's just my personal opinion. It's true that .vue not HTML, but if it doesn't comply with HTML, I think that need to document and publish the specification. I wouldn't report that the parser should be changed unless the spec is documented. Again, this is just my personal opinion. <i18n> is not <script>.

If you think that should change vue-eslint-parser, you can open the issue in the parser's repository.

wolfgangwalther commented 4 years ago

And I am not even sure that this is a bug in vue-eslint-parser. vue-eslint-parser just seems to be the wrong tool for the job. At least right now. Citing the readme of it:

This parser allows us to lint the <template> of .vue files.

So this seems specifically designed to only load <template> blocks and not custom blocks, no?

So maybe it will be more of a feature request "support loading custom blocks"?

If you think that should change vue-eslint-parser, you can open the issue in the parser's repository.

Yes, I would like to, but I don't have enough info, yet. Is it correct that vue-eslint-parser tries to parse the <i18n> block as HTML and this fails?

ota-meshi commented 4 years ago

I don't know where the custom block parsing spec is documented, so I'm not sure about the correct spec.

wolfgangwalther commented 4 years ago

I don't know where the custom block parsing spec is documented, so I'm not sure about the correct spec.

If I understand correctly, the SFC in .vue files is a concept of vue-loader. The docs for vue-loader state clearly that you can use custom blocks and mention nowhere, that those should be parsed as HTML inside: https://vue-loader.vuejs.org/guide/custom-blocks.html#example. In fact they mention that you should use custom loaders for the content - so that's a clear indication, that anyone loading the content of a custom block should not expect it to contain html without lang="html". I guess this is as much "specification" as you can get.