Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add vue/v-on-event-hyphenation rule (#1388)
* Add vue/v-on-event-hyphenation rule * update docs * Update doc
- Loading branch information
Showing
9 changed files
with
362 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
--- | ||
pageClass: rule-details | ||
sidebarDepth: 0 | ||
title: vue/v-on-event-hyphenation | ||
description: enforce v-on event naming style on custom components in template | ||
--- | ||
# vue/v-on-event-hyphenation | ||
|
||
> enforce v-on event naming style on custom components in template | ||
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge> | ||
- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. | ||
|
||
## :book: Rule Details | ||
|
||
This rule enforces using hyphenated v-on event names on custom components in Vue templates. | ||
|
||
<eslint-code-block fix :rules="{'vue/v-on-event-hyphenation': ['error', 'always', { autofix: true }]}"> | ||
|
||
```vue | ||
<template> | ||
<!-- ✓ GOOD --> | ||
<MyComponent v-on:custom-event="handleEvent"/> | ||
<MyComponent @custom-event="handleEvent"/> | ||
<!-- ✗ BAD --> | ||
<MyComponent v-on:customEvent="handleEvent"/> | ||
<MyComponent @customEvent="handleEvent"/> | ||
</template> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
## :wrench: Options | ||
|
||
```json | ||
{ | ||
"vue/v-on-event-hyphenation": ["error", "always" | "never", { | ||
"autofix": false, | ||
"ignore": [] | ||
}] | ||
} | ||
``` | ||
|
||
- `"always"` (default) ... Use hyphenated name. | ||
- `"never"` ... Don't use hyphenated name. | ||
- `"ignore"` ... Array of ignored names | ||
- `"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"` | ||
|
||
It errors on upper case letters. | ||
|
||
<eslint-code-block fix :rules="{'vue/v-on-event-hyphenation': ['error', 'always', { autofix: true }]}"> | ||
|
||
```vue | ||
<template> | ||
<!-- ✓ GOOD --> | ||
<MyComponent v-on:custom-event="handleEvent"/> | ||
<!-- ✗ BAD --> | ||
<MyComponent v-on:customEvent="handleEvent"/> | ||
</template> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
### `"never"` | ||
|
||
It errors on hyphens. | ||
|
||
<eslint-code-block fix :rules="{'vue/v-on-event-hyphenation': ['error', 'never', { autofix: true }]}"> | ||
|
||
```vue | ||
<template> | ||
<!-- ✓ GOOD --> | ||
<MyComponent v-on:customEvent="handleEvent"/> | ||
<!-- ✗ BAD --> | ||
<MyComponent v-on:custom-event="handleEvent"/> | ||
</template> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
### `"never", { "ignore": ["custom-event"] }` | ||
|
||
Don't use hyphenated name but allow custom event names | ||
|
||
<eslint-code-block fix :rules="{'vue/v-on-event-hyphenation': ['error', 'never', { ignore: ['custom-event'], autofix: true }]}"> | ||
|
||
```vue | ||
<template> | ||
<!-- ✓ GOOD --> | ||
<MyComponent v-on:custom-event="handleEvent"/> | ||
<MyComponent v-on:myEvent="handleEvent"/> | ||
<!-- ✗ BAD --> | ||
<MyComponent v-on:my-event="handleEvent"/> | ||
</template> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
## :books: Further Reading | ||
|
||
- [Guide - Custom Events] | ||
|
||
[Guide - Custom Events]: https://v3.vuejs.org/guide/component-custom-events.html | ||
|
||
## :couple: Related Rules | ||
|
||
- [vue/custom-event-name-casing](./custom-event-name-casing.md) | ||
- [vue/attribute-hyphenation](./attribute-hyphenation.md) | ||
|
||
## :mag: Implementation | ||
|
||
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/v-on-event-hyphenation.js) | ||
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/v-on-event-hyphenation.js) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
'use strict' | ||
|
||
const utils = require('../utils') | ||
const casing = require('../utils/casing') | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: | ||
'enforce v-on event naming style on custom components in template', | ||
// TODO Change with major version. | ||
// categories: ['vue3-strongly-recommended'], | ||
categories: undefined, | ||
url: 'https://eslint.vuejs.org/rules/v-on-event-hyphenation.html' | ||
}, | ||
fixable: 'code', | ||
schema: [ | ||
{ | ||
enum: ['always', 'never'] | ||
}, | ||
{ | ||
type: 'object', | ||
properties: { | ||
autofix: { type: 'boolean' }, | ||
ignore: { | ||
type: 'array', | ||
items: { | ||
allOf: [ | ||
{ type: 'string' }, | ||
{ not: { type: 'string', pattern: ':exit$' } }, | ||
{ not: { type: 'string', pattern: '^\\s*$' } } | ||
] | ||
}, | ||
uniqueItems: true, | ||
additionalItems: false | ||
} | ||
}, | ||
additionalProperties: false | ||
} | ||
], | ||
type: 'suggestion' | ||
}, | ||
|
||
/** @param {RuleContext} context */ | ||
create(context) { | ||
const sourceCode = context.getSourceCode() | ||
const option = context.options[0] | ||
const optionsPayload = context.options[1] | ||
const useHyphenated = option !== 'never' | ||
/** @type {string[]} */ | ||
const ignoredAttributes = (optionsPayload && optionsPayload.ignore) || [] | ||
const autofix = Boolean(optionsPayload && optionsPayload.autofix) | ||
|
||
const caseConverter = casing.getExactConverter( | ||
useHyphenated ? 'kebab-case' : 'camelCase' | ||
) | ||
|
||
/** | ||
* @param {VDirective} node | ||
* @param {string} name | ||
*/ | ||
function reportIssue(node, name) { | ||
const text = sourceCode.getText(node.key) | ||
|
||
context.report({ | ||
node: node.key, | ||
loc: node.loc, | ||
message: useHyphenated | ||
? "v-on event '{{text}}' must be hyphenated." | ||
: "v-on event '{{text}}' can't be hyphenated.", | ||
data: { | ||
text | ||
}, | ||
fix: autofix | ||
? (fixer) => | ||
fixer.replaceText( | ||
node.key, | ||
text.replace(name, caseConverter(name)) | ||
) | ||
: null | ||
}) | ||
} | ||
|
||
/** | ||
* @param {string} value | ||
*/ | ||
function isIgnoredAttribute(value) { | ||
const isIgnored = ignoredAttributes.some((attr) => { | ||
return value.includes(attr) | ||
}) | ||
|
||
if (isIgnored) { | ||
return true | ||
} | ||
|
||
return useHyphenated ? value.toLowerCase() === value : !/-/.test(value) | ||
} | ||
|
||
return utils.defineTemplateBodyVisitor(context, { | ||
"VAttribute[directive=true][key.name.name='on']"(node) { | ||
if (!utils.isCustomComponent(node.parent.parent)) return | ||
|
||
const name = | ||
node.key.argument && | ||
node.key.argument.type === 'VIdentifier' && | ||
node.key.argument.rawName | ||
if (!name || isIgnoredAttribute(name)) return | ||
|
||
reportIssue(node, name) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.