Skip to content

Commit

Permalink
Add vue/require-emit-validator rule (#1487)
Browse files Browse the repository at this point in the history
* Add `vue/require-emit-types` rule

* remove from categories

* allow identifiers

* add suggestion for skipped validation

* rename rule
  • Loading branch information
g-plane committed May 29, 2021
1 parent 3da8d31 commit d03ce92
Show file tree
Hide file tree
Showing 4 changed files with 482 additions and 0 deletions.
61 changes: 61 additions & 0 deletions docs/rules/require-emit-validator.md
@@ -0,0 +1,61 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/require-emit-validator
description: require type definitions in emits
---
# vue/require-emit-validator

> require type definitions in emits
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
- :gear: This rule is included in .

## :book: Rule Details

This rule enforces that a `emits` statement contains type definition.

Declaring `emits` with types can bring better maintenance.
Even if using with TypeScript, this can provide better type inference when annotating parameters with types.

<eslint-code-block :rules="{'vue/require-emit-validator': ['error']}">

```vue
<script>
/* ✓ GOOD */
Vue.component('foo', {
emits: {
// Emit with arguments
foo: (payload) => { /* validate payload */ },
// Emit without parameters
bar: () => true,
}
})
/* ✗ BAD */
Vue.component('bar', {
emits: ['foo']
})
Vue.component('baz', {
emits: {
foo: null,
}
})
</script>
```

</eslint-code-block>

## :wrench: Options

Nothing.

## :books: Further Reading

- [API Reference](https://v3.vuejs.org/api/options-data.html#emits)

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/require-emit-validator.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/require-emit-validator.js)
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -140,6 +140,7 @@ module.exports = {
'require-component-is': require('./rules/require-component-is'),
'require-default-prop': require('./rules/require-default-prop'),
'require-direct-export': require('./rules/require-direct-export'),
'require-emit-validator': require('./rules/require-emit-validator'),
'require-explicit-emits': require('./rules/require-explicit-emits'),
'require-name-property': require('./rules/require-name-property'),
'require-prop-type-constructor': require('./rules/require-prop-type-constructor'),
Expand Down
90 changes: 90 additions & 0 deletions lib/rules/require-emit-validator.js
@@ -0,0 +1,90 @@
/**
* @fileoverview Emit definitions should be detailed
* @author Pig Fang
*/
'use strict'

const utils = require('../utils')

/**
* @typedef {import('../utils').ComponentArrayEmit} ComponentArrayEmit
* @typedef {import('../utils').ComponentObjectEmit} ComponentObjectEmit
*/

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'require type definitions in emits',
categories: [],
url: 'https://eslint.vuejs.org/rules/require-emit-validator.html'
},
fixable: null,
messages: {
missing: 'Emit "{{name}}" should define at least its validator function.',
skipped:
'Emit "{{name}}" should not skip validation, or you may define a validator function with no parameters.',
emptyValidation: 'Replace with a validator function with no parameters.'
},
schema: []
},
/** @param {RuleContext} context */
create(context) {
// ----------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------

/**
* @param {ComponentArrayEmit|ComponentObjectEmit} emit
*/
function checker({ value, node, emitName }) {
const hasType =
!!value &&
(value.type === 'ArrowFunctionExpression' ||
value.type === 'FunctionExpression' ||
// validator may from outer scope
value.type === 'Identifier')

if (!hasType) {
const name =
emitName ||
(node.type === 'Identifier' && node.name) ||
'Unknown emit'

if (value && value.type === 'Literal' && value.value === null) {
context.report({
node,
messageId: 'skipped',
data: { name },
suggest: [
{
messageId: 'emptyValidation',
fix: (fixer) => fixer.replaceText(value, '() => true')
}
]
})

return
}

context.report({
node,
messageId: 'missing',
data: { name }
})
}
}

// ----------------------------------------------------------------------
// Public
// ----------------------------------------------------------------------

return utils.executeOnVue(context, (obj) => {
utils.getComponentEmits(obj).forEach(checker)
})
}
}

0 comments on commit d03ce92

Please sign in to comment.