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

feat: add ignoreTags option #2609

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
26 changes: 22 additions & 4 deletions docs/rules/attribute-hyphenation.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,19 @@ This rule enforces using hyphenated attribute names on custom components in Vue
```json
{
"vue/attribute-hyphenation": ["error", "always" | "never", {
"ignore": []
"ignore": [],
"ignoreTags": []
}]
}
```

Default casing is set to `always`. By default the following attributes are ignored: `data-`, `aria-`, `slot-scope`,
and all the [SVG attributes](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute) with either an upper case letter or an hyphen.

- `"always"` (default) ... Use hyphenated name.
- `"never"` ... Don't use hyphenated name except the ones that are ignored.
- `"ignore"` ... Array of ignored names
- `"always"` (default) ... Use hyphenated attribute name.
- `"never"` ... Don't use hyphenated attribute name.
- `"ignore"` ... Array of attribute names that don't need to follow the specified casing.
- `"ignoreTags"` ... Array of tag names whose attributes don't need to follow the specified casing.

### `"always"`

Expand Down Expand Up @@ -109,6 +111,22 @@ Don't use hyphenated name but allow custom attributes

</eslint-code-block>

### `"never", { "ignoreTags": ["/^custom-/"] }`

<eslint-code-block fix :rules="{'vue/attribute-hyphenation': ['error', 'never', { ignoreTags: ['/^custom-/'] }]}">

```vue
<template>
<!-- ✓ GOOD -->
<custom-component my-prop="prop" />

<!-- ✗ BAD -->
<my-component my-prop="prop" />
</template>
```

</eslint-code-block>

## :couple: Related Rules

- [vue/v-on-event-hyphenation](./v-on-event-hyphenation.md)
Expand Down
26 changes: 22 additions & 4 deletions docs/rules/v-on-event-hyphenation.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,16 @@ This rule enforces using hyphenated v-on event names on custom components in Vue
{
"vue/v-on-event-hyphenation": ["error", "always" | "never", {
"autofix": false,
"ignore": []
"ignore": [],
"ignoreTags": []
}]
}
```

- `"always"` (default) ... Use hyphenated name.
- `"never"` ... Don't use hyphenated name.
- `"ignore"` ... Array of ignored names
- `"always"` (default) ... Use hyphenated event name.
- `"never"` ... Don't use hyphenated event name.
- `"ignore"` ... Array of event names that don't need to follow the specified casing.
- `"ignoreTags"` ... Array of tag names whose events don't need to follow the specified casing.
- `"autofix"` ... If `true`, enable autofix. If you are using Vue 2, we recommend that you do not use it due to its side effects.

### `"always"`
Expand Down Expand Up @@ -104,6 +106,22 @@ Don't use hyphenated name but allow custom event names

</eslint-code-block>

### `"never", { "ignoreTags": ["/^custom-/"] }`

<eslint-code-block fix :rules="{'vue/v-on-event-hyphenation': ['error', 'never', { ignoreTags: ['/^custom-/'], autofix: true }]}">

```vue
<template>
<!-- ✓ GOOD -->
<custom-component v-on:my-event="handleEvent" />

<!-- ✗ BAD -->
<my-component v-on:my-event="handleEvent" />
</template>
```

</eslint-code-block>

## :couple: Related Rules

- [vue/custom-event-name-casing](./custom-event-name-casing.md)
Expand Down
22 changes: 20 additions & 2 deletions lib/rules/attribute-hyphenation.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

const utils = require('../utils')
const casing = require('../utils/casing')
const { toRegExp } = require('../utils/regexp')
const svgAttributes = require('../utils/svg-attributes-weird-case.json')

/**
Expand Down Expand Up @@ -56,6 +57,12 @@ module.exports = {
},
uniqueItems: true,
additionalItems: false
},
ignoreTags: {
type: 'array',
items: { type: 'string' },
uniqueItems: true,
additionalItems: false
}
},
additionalProperties: false
Expand All @@ -72,6 +79,11 @@ module.exports = {
const option = context.options[0]
const optionsPayload = context.options[1]
const useHyphenated = option !== 'never'
/** @type {RegExp[]} */
const ignoredTagsRegexps = (
(optionsPayload && optionsPayload.ignoreTags) ||
[]
).map(toRegExp)
const ignoredAttributes = ['data-', 'aria-', 'slot-scope', ...svgAttributes]

if (optionsPayload && optionsPayload.ignore) {
Expand Down Expand Up @@ -130,11 +142,17 @@ module.exports = {
return useHyphenated ? value.toLowerCase() === value : !/-/.test(value)
}

/** @param {string} name */
function isIgnoredTagName(name) {
return ignoredTagsRegexps.some((re) => re.test(name))
}

return utils.defineTemplateBodyVisitor(context, {
VAttribute(node) {
const element = node.parent.parent
if (
!utils.isCustomComponent(node.parent.parent) &&
node.parent.parent.name !== 'slot'
(!utils.isCustomComponent(element) && element.name !== 'slot') ||
isIgnoredTagName(element.rawName)
)
return

Expand Down
25 changes: 24 additions & 1 deletion lib/rules/v-on-event-hyphenation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const utils = require('../utils')
const casing = require('../utils/casing')
const { toRegExp } = require('../utils/regexp')

module.exports = {
meta: {
Expand Down Expand Up @@ -35,6 +36,12 @@ module.exports = {
},
uniqueItems: true,
additionalItems: false
},
ignoreTags: {
type: 'array',
items: { type: 'string' },
uniqueItems: true,
additionalItems: false
}
},
additionalProperties: false
Expand All @@ -56,6 +63,11 @@ module.exports = {
const useHyphenated = option !== 'never'
/** @type {string[]} */
const ignoredAttributes = (optionsPayload && optionsPayload.ignore) || []
/** @type {RegExp[]} */
const ignoredTagsRegexps = (
(optionsPayload && optionsPayload.ignoreTags) ||
[]
).map(toRegExp)
const autofix = Boolean(optionsPayload && optionsPayload.autofix)

const caseConverter = casing.getConverter(
Expand Down Expand Up @@ -99,9 +111,20 @@ module.exports = {
return useHyphenated ? value.toLowerCase() === value : !/-/.test(value)
}

/** @param {string} name */
function isIgnoredTagName(name) {
return ignoredTagsRegexps.some((re) => re.test(name))
}

return utils.defineTemplateBodyVisitor(context, {
"VAttribute[directive=true][key.name.name='on']"(node) {
if (!utils.isCustomComponent(node.parent.parent)) return
const element = node.parent.parent
if (
!utils.isCustomComponent(element) ||
isIgnoredTagName(element.rawName)
) {
return
}
if (!node.key.argument || node.key.argument.type !== 'VIdentifier') {
return
}
Expand Down
66 changes: 66 additions & 0 deletions tests/lib/rules/attribute-hyphenation.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,26 @@ ruleTester.run('attribute-hyphenation', rule, {
filename: 'test.vue',
code: '<template><div><custom :myName.sync="prop"></custom></div></template>',
options: ['never']
},
{
filename: 'test.vue',
code: `
<template>
<VueComponent my-prop></VueComponent>
<custom-component my-prop></custom-component>
</template>
`,
options: ['never', { ignoreTags: ['VueComponent', '/^custom-/'] }]
FloEdelmann marked this conversation as resolved.
Show resolved Hide resolved
},
{
filename: 'test.vue',
code: `
<template>
<VueComponent myProp="prop"></VueComponent>
<custom-component myProp="prop"></custom-component>
</template>
`,
options: ['always', { ignoreTags: ['VueComponent', '/^custom-/'] }]
}
],

Expand Down Expand Up @@ -450,6 +470,52 @@ ruleTester.run('attribute-hyphenation', rule, {
line: 1
}
]
},
{
code: `
<template>
<custom my-prop/>
<CustomComponent my-prop/>
</template>
`,
output: `
<template>
<custom myProp/>
<CustomComponent my-prop/>
</template>
`,
options: ['never', { ignoreTags: ['CustomComponent'] }],
FloEdelmann marked this conversation as resolved.
Show resolved Hide resolved
errors: [
{
message: "Attribute 'my-prop' can't be hyphenated.",
type: 'VIdentifier',
line: 3,
column: 17
}
]
},
{
code: `
<template>
<custom myProp/>
<CustomComponent myProp/>
</template>
`,
output: `
<template>
<custom my-prop/>
<CustomComponent myProp/>
</template>
`,
options: ['always', { ignoreTags: ['CustomComponent'] }],
errors: [
{
message: "Attribute 'myProp' must be hyphenated.",
type: 'VIdentifier',
line: 3,
column: 17
}
]
}
]
})
70 changes: 70 additions & 0 deletions tests/lib/rules/v-on-event-hyphenation.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,32 @@ tester.run('v-on-event-hyphenation', rule, {
</template>
`,
options: ['never', { ignore: ['custom'] }]
},
{
code: `
<template>
<VueComponent v-on:custom-event="events"/>
</template>
`,
options: ['never', { ignore: ['custom-event'] }]
},
{
code: `
<template>
<VueComponent v-on:custom-event="events"/>
<custom-component v-on:custom-event="events"/>
</template>
`,
options: ['never', { ignoreTags: ['/^Vue/', 'custom-component'] }]
},
{
code: `
<template>
<VueComponent v-on:customEvent="events"/>
<custom-component v-on:customEvent="events"/>
</template>
`,
options: ['always', { ignoreTags: ['/^Vue/', 'custom-component'] }]
}
],
invalid: [
Expand Down Expand Up @@ -179,6 +205,50 @@ tester.run('v-on-event-hyphenation', rule, {
"v-on event '@upDate:model-value' can't be hyphenated.",
"v-on event '@up-date:model-value' can't be hyphenated."
]
},
{
code: `
<template>
<VueComponent v-on:custom-event="events"/>
<CustomComponent v-on:custom-event="events"/>
</template>
`,
output: `
<template>
<VueComponent v-on:customEvent="events"/>
<CustomComponent v-on:custom-event="events"/>
</template>
`,
options: ['never', { autofix: true, ignoreTags: ['CustomComponent'] }],
errors: [
{
message: "v-on event 'v-on:custom-event' can't be hyphenated.",
line: 3,
column: 23
}
]
},
{
code: `
<template>
<VueComponent v-on:customEvent="events"/>
<CustomComponent v-on:customEvent="events"/>
</template>
`,
output: `
<template>
<VueComponent v-on:custom-event="events"/>
<CustomComponent v-on:customEvent="events"/>
</template>
`,
options: ['always', { autofix: true, ignoreTags: ['CustomComponent'] }],
errors: [
{
message: "v-on event 'v-on:customEvent' must be hyphenated.",
line: 3,
column: 23
}
]
}
]
})
Loading