Subscribe on changes!

`foo-bar` is not convert to `FooBar` but the code completion says so

avatar
Jul 19th 2023

Vue version

3.3.4

Link to minimal reproduction

https://play.vuejs.org/#eNp9UstOwzAQ/BXLpyIVR6i3Kq1EUZHgABXl6ENDuklTHK9lO6VSlH9n7ZAGicclys7MjsfrbfmtMeLUAJ/z1OW2Mp458I1ZSl3VBq1nd1gbVlismeQiCVXQSy611GnS95CaCg+1UZkHqhhLY9+8QLx+y+xC8t0BlMKd5AnxaXIR8yn3LkddVKU4OtSUpA0GkufkUCmwz8ZXqJ3kcxaZwGXk9fEYMW8bmA54foD8/Rf86M4Bk3xjwYE90QUunM9sCb6n19snONP/haxx3yhS/0O+gEPVhIy9bNXoPcX+potpH+I8K12+uvXZg3bDpULQoOyiXnIabxjeX1cf487ELPZJ3dEUh6f5+ZRWahqw88xYNI4t2B6KSsMmVJM20MH5HnGV2TnbekshA9pdhe/QjgqEwnLSCiGi0UiPezAA4y5E9/Rws2zbryNY16UJAX3nuAjdJ/5i3S4=

Steps to reproduce

  1. Create a component
<script setup>
const props = defineProps({
    FooBar: String
})

console.log({...props})

</script>

<template>
  <h1>{{ FooBar }}</h1>
</template>
  1. use it like this
<script setup>
import Comp from "./Comp.vue"

</script>

<template>
  <Comp :foo-bar="`hello`"/>
</template>
  1. see the code completion image

What is expected?

renders hello, OR code completion should not give me foo-bar

What is actually happening?

renders nothing

System Info

No response

Any additional comments?

No response

avatar
Jul 19th 2023

/cc @so1ve duty call šŸ¤­

avatar
Jul 19th 2023

@edison1105 šŸ¤”šŸ¤” I guess you need to transfer this issue to vuejs/language-tools :))))))

avatar
Jul 19th 2023

@Justineo image

avatar
Jul 19th 2023
<Comp :foo-bar="`hello`"/>

is equal to

<Comp :fooBar="`hello`"/>

is not equal to

<Comp :FooBar="`hello`"/>

In the implementation of Vue, the key of props is only determined for equality using camelize(key), so fooBar and FooBar can coexist and represent two different props.

<script setup>
const props = defineProps({
    FooBar: String,
    fooBar: String
})

console.log({...props})

</script>

<template>
  <h1>{{fooBar}} {{ FooBar }} </h1>
</template>
<script setup>
import Comp from "./Comp.vue"

</script>

<template>
  <Comp :foo-bar="`hello`" :FooBar="`world`" />
</template>
avatar
Jul 19th 2023

That's definitely a bug. In that case, we have to convert FooBar to -foo-bar, which is not vue's shared hyphenate utility's desired output. We will use a custom hyphenate function in volar side. Fix for this issue will be available at vuejs/language-tools#3424

avatar
Jul 19th 2023

In fact, the hyphenate function and the camelize function are not reversible to each other. For example, camelize(hyphenate('FooBar')) == 'fooBar', which has lost the information of the capital letter "F". Therefore, if language-tools uses hyphenate to achieve the opposite effect of camelize, it must be aware that camelize does not perform any processing on the letter before the first hyphen. For example, the following equations must hold to achieve the expected behavior:

hyphenate('FooBar') === 'Foo-bar'
hyphenate('fooBar') === 'foo-bar'
avatar
Jul 19th 2023

Yes, I just simply checked if the argument begins with a capital letter. If so, I add a - before the result

avatar
Jul 20th 2023

@so1ve Hmm I made a mistake when I found :-foo-bar actually works in this case. But Iā€™m still not sure what shall we suggest for prop FooBar on the Volar side.

avatar
Jul 20th 2023

@Justineo I think -foo-bar is ok?

avatar
Jul 20th 2023

Or shall we just warn about using PascalCased props?

avatar
Jul 20th 2023

@Justineo that's an edge case IMO. Should vue forbid this usage?

avatar
Jul 27th 2023

Kind of a side question, but isn't it a bit weird that Vue is converting TitleCase props to start with a dash: "-title-case", when <component -title-case="foo" /> isn't really valid as a custom html tag?