Skip to content

Commit d815a48

Browse files
authored
Add vue/require-macro-variable-name rule (#2198)
1 parent 13167ed commit d815a48

File tree

5 files changed

+521
-0
lines changed

5 files changed

+521
-0
lines changed

docs/rules/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ For example:
262262
| [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | | :hammer: |
263263
| [vue/require-emit-validator](./require-emit-validator.md) | require type definitions in emits | :bulb: | :hammer: |
264264
| [vue/require-expose](./require-expose.md) | require declare public properties using `expose` | :bulb: | :hammer: |
265+
| [vue/require-macro-variable-name](./require-macro-variable-name.md) | require a certain macro variable name | :bulb: | :hammer: |
265266
| [vue/require-name-property](./require-name-property.md) | require a name property in Vue components | :bulb: | :hammer: |
266267
| [vue/require-prop-comment](./require-prop-comment.md) | require props to have a comment | | :hammer: |
267268
| [vue/script-indent](./script-indent.md) | enforce consistent indentation in `<script>` | :wrench: | :lipstick: |
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/require-macro-variable-name
5+
description: require a certain macro variable name
6+
---
7+
# vue/require-macro-variable-name
8+
9+
> require a certain macro variable name
10+
11+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
12+
- :bulb: Some problems reported by this rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
13+
14+
## :book: Rule Details
15+
16+
This rule reports macro variables not corresponding to the specified name.
17+
18+
<eslint-code-block :rules="{'vue/require-macro-variable-name': ['error']}">
19+
20+
```vue
21+
<!-- ✓ GOOD -->
22+
<script setup>
23+
const props = defineProps({ msg: String })
24+
const emit = defineEmits(['update:msg'])
25+
</script>
26+
```
27+
28+
</eslint-code-block>
29+
30+
<eslint-code-block :rules="{'vue/require-macro-variable-name': ['error']}">
31+
32+
```vue
33+
<!-- ✗ BAD -->
34+
<script setup>
35+
const propsDefined = defineProps({ msg: String })
36+
const emitsDefined = defineEmits(['update:msg'])
37+
</script>
38+
```
39+
40+
</eslint-code-block>
41+
42+
## :wrench: Options
43+
44+
```json
45+
{
46+
"vue/require-macro-variable-name": ["error", {
47+
"defineProps": "props",
48+
"defineEmits": "emit",
49+
"defineSlots": "slots",
50+
"useSlots": "slots",
51+
"useAttrs": "attrs"
52+
}]
53+
}
54+
```
55+
56+
- `defineProps` - The name of the macro variable for `defineProps`. default: `props`
57+
- `defineEmits` - The name of the macro variable for `defineEmits`. default: `emit`
58+
- `defineSlots` - The name of the macro variable for `defineSlots`. default: `slots`
59+
- `useSlots` - The name of the macro variable for `useSlots`. default: `slots`
60+
- `useAttrs` - The name of the macro variable for `useAttrs`. default: `attrs`
61+
62+
### With custom macro variable names
63+
64+
<eslint-code-block :rules="{'vue/require-macro-variable-name': ['error', {
65+
'defineProps': 'propsCustom',
66+
'defineEmits': 'emitCustom',
67+
'defineSlots': 'slotsCustom',
68+
'useSlots': 'slotsCustom',
69+
'useAttrs': 'attrsCustom'
70+
}]}">
71+
72+
```vue
73+
<script setup>
74+
const slotsCustom = defineSlots()
75+
const attrsCustom = useAttrs()
76+
</script>
77+
```
78+
79+
</eslint-code-block>
80+
81+
## :mag: Implementation
82+
83+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/require-macro-variable-name.js)
84+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/require-macro-variable-name.js)

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ module.exports = {
181181
'require-emit-validator': require('./rules/require-emit-validator'),
182182
'require-explicit-emits': require('./rules/require-explicit-emits'),
183183
'require-expose': require('./rules/require-expose'),
184+
'require-macro-variable-name': require('./rules/require-macro-variable-name'),
184185
'require-name-property': require('./rules/require-name-property'),
185186
'require-prop-comment': require('./rules/require-prop-comment'),
186187
'require-prop-type-constructor': require('./rules/require-prop-type-constructor'),
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* @author ItMaga
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const utils = require('../utils')
8+
9+
const DEFAULT_OPTIONS = {
10+
defineProps: 'props',
11+
defineEmits: 'emit',
12+
defineSlots: 'slots',
13+
useSlots: 'slots',
14+
useAttrs: 'attrs'
15+
}
16+
17+
module.exports = {
18+
meta: {
19+
hasSuggestions: true,
20+
type: 'suggestion',
21+
docs: {
22+
description: 'require a certain macro variable name',
23+
categories: undefined,
24+
url: 'https://eslint.vuejs.org/rules/require-macro-variable-name.html'
25+
},
26+
fixable: null,
27+
schema: [
28+
{
29+
type: 'object',
30+
properties: {
31+
defineProps: {
32+
type: 'string',
33+
default: DEFAULT_OPTIONS.defineProps
34+
},
35+
defineEmits: {
36+
type: 'string',
37+
default: DEFAULT_OPTIONS.defineEmits
38+
},
39+
defineSlots: {
40+
type: 'string',
41+
default: DEFAULT_OPTIONS.defineSlots
42+
},
43+
useSlots: {
44+
type: 'string',
45+
default: DEFAULT_OPTIONS.useSlots
46+
},
47+
useAttrs: {
48+
type: 'string',
49+
default: DEFAULT_OPTIONS.useAttrs
50+
}
51+
},
52+
additionalProperties: false
53+
}
54+
],
55+
messages: {
56+
requireName:
57+
'The variable name of "{{macroName}}" must be "{{variableName}}".',
58+
changeName: 'Change the variable name to "{{variableName}}".'
59+
}
60+
},
61+
/** @param {RuleContext} context */
62+
create(context) {
63+
const options = context.options[0] || DEFAULT_OPTIONS
64+
const relevantMacros = new Set([
65+
...Object.keys(DEFAULT_OPTIONS),
66+
'withDefaults'
67+
])
68+
69+
return utils.defineScriptSetupVisitor(context, {
70+
VariableDeclarator(node) {
71+
if (
72+
node.init &&
73+
node.init.type === 'CallExpression' &&
74+
node.init.callee.type === 'Identifier' &&
75+
relevantMacros.has(node.init.callee.name)
76+
) {
77+
const macroName =
78+
node.init.callee.name === 'withDefaults'
79+
? 'defineProps'
80+
: node.init.callee.name
81+
82+
if (
83+
node.id.type === 'Identifier' &&
84+
node.id.name !== options[macroName]
85+
) {
86+
context.report({
87+
node: node.id,
88+
loc: node.id.loc,
89+
messageId: 'requireName',
90+
data: {
91+
macroName,
92+
variableName: options[macroName]
93+
},
94+
suggest: [
95+
{
96+
messageId: 'changeName',
97+
data: {
98+
variableName: options[macroName]
99+
},
100+
fix(fixer) {
101+
return fixer.replaceText(node.id, options[macroName])
102+
}
103+
}
104+
]
105+
})
106+
}
107+
}
108+
}
109+
})
110+
}
111+
}

0 commit comments

Comments
 (0)