vuejs / eslint-plugin-vue

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

Namespace handling makes it impossible to lint recursive SVG / MathML components #2458

Open mordae opened 6 months ago

mordae commented 6 months ago

What rule do you want to change?

Not exactly a specific rule, but I have been motivated by vue/no-v-text-v-html-on-component being falsely triggered on MathML tags. isCustomComponent() is being called from 17 rules. The problem lies with the fact that every composition component starts with a top-level namespace of HTML, which makes it impossible to create partial, especially recursive components within another namespace without confusing the linter.

Does this change cause the rule to produce more or fewer warnings?

Fewer.

How will the change be implemented? (New option, new default behavior, etc.)?

There are multiple options:

  1. Stop examining namespaces when determining whether something is an element or a component.
  2. Treat the HTML namespace as valid namespace for SVG and MathML tags.
  3. Looks for xmlns on the top-level <template/> and adjust namespace accordingly.
  4. Implement (1) or (2), but gate it behind a configuration option.

Please provide some example code that this change will affect:

<script setup type="ts">
// This lives inside MathExpression.vue

import { Expression } from './expression.ts'

defineProps<{
  expression: Expression
}>()
</script>

<template>
  <mfrac v-if="expression instanceof Fraction">
    <mrow>
      <MathExpression v-text="expression.numerator" />
    </mrow>
    <mrow>
      <MathExpression v-text="expression.denominator" />
    </mrow>
  </mfrac>
  <!-- more cases omitted for brevity -->
  <mn v-else v-text="expression.value" />
</template>

What does the rule currently do for this code?

Triggers vue/no-v-text-v-html-on-component because it does not see <mfrac/> as being inside MathML namespace. Which is impossible to realize, because <math/> cannot be nested and is only specified at the top level. This component recurses into the data, rendering the full MathML structure.

What will the rule do after it's changed?

In case of (1), (2), (4) it won't consider using <mfrac/> in this context as an error. In case of (3):

<template xmlns="http://www.w3.org/1998/Math/MathML">
  <mi v-text="'x'" />
</template>

It will accept this otherwise invalid, but (probably) harmless syntax to indicate that we are inside MathML namespace and proceed from there on, possibly marking HTML and SVG elements as out of place.

Additional context

This obviously applies to SVG as well, although there is not that high probability somebody will be doing anything recursive in there. Math is a different story, though.

waynzh commented 5 months ago

Maybe fixed by https://github.com/vuejs/eslint-plugin-vue/pull/2457, and we can close this right?

FloEdelmann commented 5 months ago

Yes, probably. Thanks for checking!

If the issue persists with the newest version of eslint-plugin-vue, please add a comment or open a new issue.

mordae commented 4 months ago

@FloEdelmann: #2457 adds support for MathML that does not span across multiple files. The issue in this report concerns MathML spanning across multiple components and is still present as described at the top.

FloEdelmann commented 4 months ago

I'm not sure which issue you are reporting exactly. Is an vue/no-v-text-v-html-on-component error reported for <MathExpression v-text="expression.numerator" />? That seems correct to me, regardless whether it is MathML or not. Or is it reported for <mn v-else v-text="expression.value" /> because it is not correctly recognized as a MathML element? But you mention the <mfrac /> element?

Could you please create a reproduction on playground, Stackblitz, or a separate repository?

mordae commented 3 months ago

Parent.vue:

<template>
  <math xmlns="http://www.w3.org/1998/Math/MathML">
    <Child />
  </math>
</template>

Child.vue:

<template>
  <mi v-text="'x'" />  <!-- vue/no-v-text-v-html-on-component -->
</template>
mordae commented 1 month ago

@FloEdelmann: playground example (with the usage described in the previous comment)

FloEdelmann commented 1 month ago

I think I finally understand, thanks for your persistence and for the playground example.

v-text on MathML elements is already ignored by the vue/no-v-text-v-html-on-component rule (and related rules, via the isCustomComponent util), but only if an ancestor element is found with the MathML namespace. If you extract the child element into a separate component, the MathML namespace can't be found anymore, so the rule reports an error.

As a workaround, you could specify { "allow": ["mi"] } as a rule option.

@mordae Do you think this suffices or would you prefer another configuration option (something like ignoreElementNamespaces, which would be false by default → same behavior as now)? @ota-meshi What do you think?

mordae commented 1 month ago

@FloEdelmann: as I've written initially, it would be nice to relax the namespace check somehow. Allowing SVG and MathML inside HTML namespace as an option would be sufficient.