Skip to content

Commit

Permalink
Add vue/require-macro-variable-name rule (vuejs#2198)
Browse files Browse the repository at this point in the history
  • Loading branch information
ItMaga authored Jun 1, 2023
1 parent 13167ed commit d815a48
Show file tree
Hide file tree
Showing 5 changed files with 521 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ For example:
| [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | | :hammer: |
| [vue/require-emit-validator](./require-emit-validator.md) | require type definitions in emits | :bulb: | :hammer: |
| [vue/require-expose](./require-expose.md) | require declare public properties using `expose` | :bulb: | :hammer: |
| [vue/require-macro-variable-name](./require-macro-variable-name.md) | require a certain macro variable name | :bulb: | :hammer: |
| [vue/require-name-property](./require-name-property.md) | require a name property in Vue components | :bulb: | :hammer: |
| [vue/require-prop-comment](./require-prop-comment.md) | require props to have a comment | | :hammer: |
| [vue/script-indent](./script-indent.md) | enforce consistent indentation in `<script>` | :wrench: | :lipstick: |
Expand Down
84 changes: 84 additions & 0 deletions docs/rules/require-macro-variable-name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/require-macro-variable-name
description: require a certain macro variable name
---
# vue/require-macro-variable-name

> require a certain macro variable name
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
- :bulb: Some problems reported by this rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).

## :book: Rule Details

This rule reports macro variables not corresponding to the specified name.

<eslint-code-block :rules="{'vue/require-macro-variable-name': ['error']}">

```vue
<!-- ✓ GOOD -->
<script setup>
const props = defineProps({ msg: String })
const emit = defineEmits(['update:msg'])
</script>
```

</eslint-code-block>

<eslint-code-block :rules="{'vue/require-macro-variable-name': ['error']}">

```vue
<!-- ✗ BAD -->
<script setup>
const propsDefined = defineProps({ msg: String })
const emitsDefined = defineEmits(['update:msg'])
</script>
```

</eslint-code-block>

## :wrench: Options

```json
{
"vue/require-macro-variable-name": ["error", {
"defineProps": "props",
"defineEmits": "emit",
"defineSlots": "slots",
"useSlots": "slots",
"useAttrs": "attrs"
}]
}
```

- `defineProps` - The name of the macro variable for `defineProps`. default: `props`
- `defineEmits` - The name of the macro variable for `defineEmits`. default: `emit`
- `defineSlots` - The name of the macro variable for `defineSlots`. default: `slots`
- `useSlots` - The name of the macro variable for `useSlots`. default: `slots`
- `useAttrs` - The name of the macro variable for `useAttrs`. default: `attrs`

### With custom macro variable names

<eslint-code-block :rules="{'vue/require-macro-variable-name': ['error', {
'defineProps': 'propsCustom',
'defineEmits': 'emitCustom',
'defineSlots': 'slotsCustom',
'useSlots': 'slotsCustom',
'useAttrs': 'attrsCustom'
}]}">

```vue
<script setup>
const slotsCustom = defineSlots()
const attrsCustom = useAttrs()
</script>
```

</eslint-code-block>

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/require-macro-variable-name.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/require-macro-variable-name.js)
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ module.exports = {
'require-emit-validator': require('./rules/require-emit-validator'),
'require-explicit-emits': require('./rules/require-explicit-emits'),
'require-expose': require('./rules/require-expose'),
'require-macro-variable-name': require('./rules/require-macro-variable-name'),
'require-name-property': require('./rules/require-name-property'),
'require-prop-comment': require('./rules/require-prop-comment'),
'require-prop-type-constructor': require('./rules/require-prop-type-constructor'),
Expand Down
111 changes: 111 additions & 0 deletions lib/rules/require-macro-variable-name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* @author ItMaga
* See LICENSE file in root directory for full license.
*/
'use strict'

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

const DEFAULT_OPTIONS = {
defineProps: 'props',
defineEmits: 'emit',
defineSlots: 'slots',
useSlots: 'slots',
useAttrs: 'attrs'
}

module.exports = {
meta: {
hasSuggestions: true,
type: 'suggestion',
docs: {
description: 'require a certain macro variable name',
categories: undefined,
url: 'https://eslint.vuejs.org/rules/require-macro-variable-name.html'
},
fixable: null,
schema: [
{
type: 'object',
properties: {
defineProps: {
type: 'string',
default: DEFAULT_OPTIONS.defineProps
},
defineEmits: {
type: 'string',
default: DEFAULT_OPTIONS.defineEmits
},
defineSlots: {
type: 'string',
default: DEFAULT_OPTIONS.defineSlots
},
useSlots: {
type: 'string',
default: DEFAULT_OPTIONS.useSlots
},
useAttrs: {
type: 'string',
default: DEFAULT_OPTIONS.useAttrs
}
},
additionalProperties: false
}
],
messages: {
requireName:
'The variable name of "{{macroName}}" must be "{{variableName}}".',
changeName: 'Change the variable name to "{{variableName}}".'
}
},
/** @param {RuleContext} context */
create(context) {
const options = context.options[0] || DEFAULT_OPTIONS
const relevantMacros = new Set([
...Object.keys(DEFAULT_OPTIONS),
'withDefaults'
])

return utils.defineScriptSetupVisitor(context, {
VariableDeclarator(node) {
if (
node.init &&
node.init.type === 'CallExpression' &&
node.init.callee.type === 'Identifier' &&
relevantMacros.has(node.init.callee.name)
) {
const macroName =
node.init.callee.name === 'withDefaults'
? 'defineProps'
: node.init.callee.name

if (
node.id.type === 'Identifier' &&
node.id.name !== options[macroName]
) {
context.report({
node: node.id,
loc: node.id.loc,
messageId: 'requireName',
data: {
macroName,
variableName: options[macroName]
},
suggest: [
{
messageId: 'changeName',
data: {
variableName: options[macroName]
},
fix(fixer) {
return fixer.replaceText(node.id, options[macroName])
}
}
]
})
}
}
}
})
}
}
Loading

0 comments on commit d815a48

Please sign in to comment.