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

Add suggestion for vue/require-name-property rule #2034

Merged
merged 1 commit into from Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/rules/README.md
Expand Up @@ -259,7 +259,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-name-property](./require-name-property.md) | require a name property in Vue components | | :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: |
| [vue/sort-keys](./sort-keys.md) | enforce sort-keys in a manner that is compatible with order-in-components | | :hammer: |
Expand Down
2 changes: 2 additions & 0 deletions docs/rules/require-name-property.md
Expand Up @@ -9,6 +9,8 @@ since: v6.1.0

> require a name property in Vue components

- :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 requires a `name` property to be set on components.
Expand Down
59 changes: 58 additions & 1 deletion lib/rules/require-name-property.js
Expand Up @@ -4,9 +4,31 @@
*/
'use strict'

const path = require('path')
const utils = require('../utils')
const { getVueComponentDefinitionType } = require('../utils')
/**
* Get the text of the empty indentation part of the line which the given token is on.
* @param {SourceCode} sourceCode the source code object
* @param {Token} token the token to get the indentation text of the line which the token is on
* @returns {string} The text of indentation part.
*/
function getLineEmptyIndent(sourceCode, token) {
const LT_CHAR = /[\n\r\u2028\u2029]/
const EMPTY_CHAR = /\s/
const text = sourceCode.text
let i = token.range[0] - 1

while (i >= 0 && !LT_CHAR.test(text[i])) {
i -= 1
}
let j = i
while (EMPTY_CHAR.test(text[j])) {
j += 1
}

return text.slice(i + 1, j)
}
/**
* @param {Property | SpreadElement} node
* @returns {node is ObjectExpressionProperty}
Expand All @@ -28,6 +50,7 @@ module.exports = {
url: 'https://eslint.vuejs.org/rules/require-name-property.html'
},
fixable: null,
hasSuggestions: true,
small-tou marked this conversation as resolved.
Show resolved Hide resolved
schema: []
},
/** @param {RuleContext} context */
Expand All @@ -47,7 +70,41 @@ module.exports = {

context.report({
node: component,
message: 'Required name property is not set.'
message: 'Required name property is not set.',
suggest: [
{
desc: 'Add name property to component.',
fix(fixer) {
const extension = path.extname(context.getFilename())
const filename = path.basename(context.getFilename(), extension)
const sourceCode = context.getSourceCode()
// fix only when property is not empty
if (component.properties.length > 0) {
const firstToken = sourceCode.getFirstToken(
component.properties[0]
)
const indentText = getLineEmptyIndent(sourceCode, firstToken)
// insert name property before the first property
return fixer.insertTextBefore(
component.properties[0],
`name: '${filename}',\n${indentText}`
)
}

const firstToken = sourceCode.getFirstToken(component)
const lastToken = sourceCode.getLastToken(component)
// if the component is empty, insert name property and indent
if (firstToken.value === '{' && lastToken.value === '}') {
const indentText = getLineEmptyIndent(sourceCode, firstToken)
return fixer.replaceTextRange(
[firstToken.range[1], lastToken.range[0]],
`\n${indentText} name: '${filename}'\n${indentText}`
)
}
return null
}
}
]
})
})
}
Expand Down
150 changes: 146 additions & 4 deletions tests/lib/rules/require-name-property.js
Expand Up @@ -78,25 +78,143 @@ ruleTester.run('require-name-property', rule, {
errors: [
{
message: 'Required name property is not set.',
type: 'ObjectExpression'
type: 'ObjectExpression',
suggestions: [
{
desc: 'Add name property to component.',
output: `
export default {
name: 'InvalidComponent'
}
`
}
]
}
]
},
{
filename: 'InvalidComponent.vue',
code: `
export default defineComponent({
})
`,
parserOptions,
errors: [
{
message: 'Required name property is not set.',
type: 'ObjectExpression',
suggestions: [
{
desc: 'Add name property to component.',
output: `
export default defineComponent({
name: 'InvalidComponent'
})
`
}
]
}
]
},
{
filename: 'InvalidComponent.vue',
code: `
export default defineComponent({ })
`,
parserOptions,
errors: [
{
message: 'Required name property is not set.',
type: 'ObjectExpression',
suggestions: [
{
desc: 'Add name property to component.',
output: `
export default defineComponent({
name: 'InvalidComponent'
})
`
}
]
}
]
},
{
filename: 'InvalidComponent.vue',
code: `
export default { }
`,
parserOptions,
errors: [
{
message: 'Required name property is not set.',
type: 'ObjectExpression',
suggestions: [
{
desc: 'Add name property to component.',
output: `
export default {
name: 'InvalidComponent'
}
`
}
]
}
]
},
{
filename: 'InvalidComponent.vue',
code: `
export default {
nameNot: 'IssaNameNot'
}
`,
parserOptions,
errors: [
{
message: 'Required name property is not set.',
type: 'ObjectExpression',
suggestions: [
{
desc: 'Add name property to component.',
output: `
export default {
name: 'InvalidComponent',
nameNot: 'IssaNameNot'
}
`
}
]
}
]
},
{
filename: 'InvalidComponent.vue',
code: `
export default defineComponent({
nameNot: 'IssaNameNot'
})
`,
parserOptions,
errors: [
{
message: 'Required name property is not set.',
type: 'ObjectExpression'
type: 'ObjectExpression',
suggestions: [
{
desc: 'Add name property to component.',
output: `
export default defineComponent({
name: 'InvalidComponent',
nameNot: 'IssaNameNot'
})
`
}
]
}
]
},

{
filename: 'InvalidComponent.vue',
code: `
Expand All @@ -110,7 +228,20 @@ ruleTester.run('require-name-property', rule, {
errors: [
{
message: 'Required name property is not set.',
type: 'ObjectExpression'
type: 'ObjectExpression',
suggestions: [
{
desc: 'Add name property to component.',
output: `
export default {
name: 'InvalidComponent',
computed: {
name() { return 'name' }
}
}
`
}
]
}
]
},
Expand All @@ -125,7 +256,18 @@ ruleTester.run('require-name-property', rule, {
errors: [
{
message: 'Required name property is not set.',
type: 'ObjectExpression'
type: 'ObjectExpression',
suggestions: [
{
desc: 'Add name property to component.',
output: `
export default {
name: 'InvalidComponent',
[name]: 'IssaName'
}
`
}
]
}
]
}
Expand Down