Skip to content

Commit

Permalink
Fix vuejs#1373: Add rule no-invalid-attribute-name
Browse files Browse the repository at this point in the history
  • Loading branch information
doug-wade committed Apr 16, 2022
1 parent a473a0d commit 325a777
Show file tree
Hide file tree
Showing 5 changed files with 258 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/rules/README.md
Expand Up @@ -12,6 +12,7 @@ sidebarDepth: 0
:bulb: Indicates that some problems reported by the rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
:::


## Base Rules (Enabling Correct ESLint Parsing)

Enforce all the rules in this category, as well as all higher priority rules, with:
Expand Down Expand Up @@ -326,6 +327,7 @@ For example:
| [vue/no-duplicate-attr-inheritance](./no-duplicate-attr-inheritance.md) | enforce `inheritAttrs` to be set to `false` when using `v-bind="$attrs"` | |
| [vue/no-empty-component-block](./no-empty-component-block.md) | disallow the `<template>` `<script>` `<style>` block to be empty | |
| [vue/no-expose-after-await](./no-expose-after-await.md) | disallow asynchronously registered `expose` | |
| [vue/no-invalid-attribute-name](./no-invalid-attribute-name.md) | require the attributes to match the imported component name | |
| [vue/no-invalid-model-keys](./no-invalid-model-keys.md) | require valid keys in model option | |
| [vue/no-multiple-objects-in-class](./no-multiple-objects-in-class.md) | disallow to pass multiple objects into array to class | |
| [vue/no-potential-component-option-typo](./no-potential-component-option-typo.md) | disallow a potential typo in your component property | :bulb: |
Expand Down
43 changes: 43 additions & 0 deletions docs/rules/no-invalid-attribute-name.md
@@ -0,0 +1,43 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/no-invalid-attribute-name
description: require the attributes to match the imported component name
---
# vue/no-invalid-attribute-name

> require the attributes to match the imported component name
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>

## :book: Rule Details

This rule detects invalid html attributes.

<eslint-code-block :rules="{'vue/no-invalid-attribute-name': ['error']}">

```vue
<template>
<!-- ✓ GOOD -->
<p foo.bar></p>
<p foo-bar></p>
<p _foo.bar></p>
<p :foo-bar></p>
<!-- ✗ BAD -->
<p 0abc></p>
<p -def></p>
<p !ghi></p>
</template>
```

</eslint-code-block>

## :wrench: Options

Nothing.

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-invalid-attribute-name.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-invalid-attribute-name.js)
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -93,6 +93,7 @@ module.exports = {
'no-export-in-script-setup': require('./rules/no-export-in-script-setup'),
'no-expose-after-await': require('./rules/no-expose-after-await'),
'no-extra-parens': require('./rules/no-extra-parens'),
'no-invalid-attribute-name': require('./rules/no-invalid-attribute-name'),
'no-invalid-model-keys': require('./rules/no-invalid-model-keys'),
'no-irregular-whitespace': require('./rules/no-irregular-whitespace'),
'no-lifecycle-after-await': require('./rules/no-lifecycle-after-await'),
Expand Down
54 changes: 54 additions & 0 deletions lib/rules/no-invalid-attribute-name.js
@@ -0,0 +1,54 @@
/**
* @author Doug Wade <douglas.b.wade@gmail.com>
* See LICENSE file in root directory for full license.
*/
'use strict'

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

module.exports = {
meta: {
type: 'problem',
docs: {
description:
'require the attributes to match the imported component name',
categories: undefined,
url: 'https://eslint.vuejs.org/rules/no-invalid-attribute-name.html'
},
fixable: null,
schema: [],
messages: {
unexpected: '{{name}} is not a valid attribute name'
}
},
/** @param {RuleContext} context */
create(context) {
/**
* @param {string | VIdentifier} key
* @return {string}
*/
const getName = (key) => {
if (typeof key === 'string') {
return key
}

return key.name
}

return utils.defineTemplateBodyVisitor(context, {
VAttribute(node) {
const name = getName(node.key.name)

if (!/^[_:a-zA-Z][_:.\-a-zA-Z0-9]+/.test(name)) {
context.report({
node,
messageId: 'unexpected',
data: {
name
}
})
}
}
})
}
}
158 changes: 158 additions & 0 deletions tests/lib/rules/no-invalid-attribute-name.js
@@ -0,0 +1,158 @@
/**
* @author *****your name*****
* See LICENSE file in root directory for full license.
*/
'use strict'

const RuleTester = require('eslint').RuleTester
const rule = require('../../../lib/rules/no-invalid-attribute-name')

const tester = new RuleTester({
parser: require.resolve('vue-eslint-parser'),
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module'
}
})

tester.run('no-invalid-attribute-name', rule, {
valid: [
{
filename: 'test.vue',
code: `
<template>
<div>
<p foo>
{{ content }}
</p>
</div>
</template>
`
},
{
filename: 'test.vue',
code: `
<template>
<div>
<p foo="bar">
{{ content }}
</p>
</div>
</template>
`
},
{
filename: 'test.vue',
code: `
<template>
<div>
<p foo-bar>
{{ content }}
</p>
</div>
</template>
`
},
{
filename: 'test.vue',
code: `
<template>
<div>
<p _foo-bar>
{{ content }}
</p>
</div>
</template>
`
},
{
filename: 'test.vue',
code: `
<template>
<div>
<p :foo-bar>
{{ content }}
</p>
</div>
</template>
`
},
{
filename: 'test.vue',
code: `
<template>
<div>
<p foo.bar>
{{ content }}
</p>
</div>
</template>
`
},
{
filename: 'test.vue',
code: `
<template>
<div>
<p quux-.9>
{{ content }}
</p>
</div>
</template>
`
}
],
invalid: [
{
filename: 'test.vue',
code: `
<template>
<div>
<p 0abc>
{{ content }}
</p>
</div>
</template>
`,
errors: [
{
message: '0abc is not a valid attribute name'
}
]
},
{
filename: 'test.vue',
code: `
<template>
<div>
<p -def>
{{ content }}
</p>
</div>
</template>
`,
errors: [
{
message: '-def is not a valid attribute name'
}
]
},
{
filename: 'test.vue',
code: `
<template>
<div>
<p !ghi>
{{ content }}
</p>
</div>
</template>
`,
errors: [
{
message: '!ghi is not a valid attribute name'
}
]
}
]
})

0 comments on commit 325a777

Please sign in to comment.