Skip to content

Commit

Permalink
⭐️New: Add vue/no-deprecated-slot-scope-attribute rule (#840)
Browse files Browse the repository at this point in the history
* ⭐️New: Add vue/no-deprecated-slot-scope-attribute rule

* Changed not to autofix, if it becomes an invalid attribute

* Changed to not autofix, if if the element have `v-bind:slot`

* Change to autofix
  • Loading branch information
ota-meshi committed Dec 26, 2019
1 parent 3306b03 commit a5fd31e
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/rules/README.md
Expand Up @@ -155,6 +155,7 @@ For example:
| [vue/no-boolean-default](./no-boolean-default.md) | disallow boolean defaults | :wrench: |
| [vue/no-deprecated-slot-attribute](./no-deprecated-slot-attribute.md) | disallow deprecated `slot` attribute (in Vue.js 2.6.0+) | :wrench: |
| [vue/no-deprecated-scope-attribute](./no-deprecated-scope-attribute.md) | disallow deprecated `scope` attribute (in Vue.js 2.5.0+) | :wrench: |
| [vue/no-deprecated-slot-scope-attribute](./no-deprecated-slot-scope-attribute.md) | disallow deprecated `slot-scope` attribute (in Vue.js 2.6.0+) | :wrench: |
| [vue/no-empty-pattern](./no-empty-pattern.md) | disallow empty destructuring patterns | |
| [vue/no-reserved-component-names](./no-reserved-component-names.md) | disallow the use of reserved names in component definitions | |
| [vue/no-restricted-syntax](./no-restricted-syntax.md) | disallow specified syntax | |
Expand Down
44 changes: 44 additions & 0 deletions docs/rules/no-deprecated-slot-scope-attribute.md
@@ -0,0 +1,44 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/no-deprecated-slot-scope-attribute
description: disallow deprecated `slot-scope` attribute (in Vue.js 2.6.0+)
---
# vue/no-deprecated-slot-scope-attribute
> disallow deprecated `slot-scope` attribute (in Vue.js 2.6.0+)
- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.

## :book: Rule Details

This rule reports deprecated `slot-scope` attribute in Vue.js v2.6.0+.

<eslint-code-block fix :rules="{'vue/no-deprecated-slot-scope-attribute': ['error']}">

```vue
<template>
<ListComponent>
<!-- ✓ GOOD -->
<template v-slot="props">
{{ props.title }}
</template>
</ListComponent>
<ListComponent>
<!-- ✗ BAD -->
<template slot-scope="props">
{{ props.title }}
</template>
</ListComponent>
</template>
```

</eslint-code-block>

## :books: Further reading

- [API - slot-scope](https://vuejs.org/v2/api/#slot-scope-deprecated)

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-deprecated-slot-scope-attribute.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-deprecated-slot-scope-attribute.js)
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -39,6 +39,7 @@ module.exports = {
'no-confusing-v-for-v-if': require('./rules/no-confusing-v-for-v-if'),
'no-deprecated-slot-attribute': require('./rules/no-deprecated-slot-attribute'),
'no-deprecated-scope-attribute': require('./rules/no-deprecated-scope-attribute'),
'no-deprecated-slot-scope-attribute': require('./rules/no-deprecated-slot-scope-attribute'),
'no-dupe-keys': require('./rules/no-dupe-keys'),
'no-duplicate-attributes': require('./rules/no-duplicate-attributes'),
'no-empty-pattern': require('./rules/no-empty-pattern'),
Expand Down
28 changes: 28 additions & 0 deletions lib/rules/no-deprecated-slot-scope-attribute.js
@@ -0,0 +1,28 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'

const utils = require('../utils')
const slotScopeAttribute = require('./syntaxes/slot-scope-attribute')

module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'disallow deprecated `slot-scope` attribute (in Vue.js 2.6.0+)',
category: undefined,
url: 'https://eslint.vuejs.org/rules/no-deprecated-slot-scope-attribute.html'
},
fixable: 'code',
schema: [],
messages: {
forbiddenSlotScopeAttribute: '`slot-scope` are deprecated.'
}
},
create (context) {
const templateBodyVisitor = slotScopeAttribute.createTemplateBodyVisitor(context, { fixToUpgrade: true })
return utils.defineTemplateBodyVisitor(context, templateBodyVisitor)
}
}
84 changes: 84 additions & 0 deletions lib/rules/syntaxes/slot-scope-attribute.js
@@ -0,0 +1,84 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
module.exports = {
deprecated: '2.6.0',
supported: '2.5.0',
createTemplateBodyVisitor (context, { fixToUpgrade } = {}) {
const sourceCode = context.getSourceCode()

/**
* Checks whether the given node can convert to the `v-slot`.
* @param {VStartTag} startTag node of `<element v-slot ... >`
* @returns {boolean} `true` if the given node can convert to the `v-slot`
*/
function canConvertToVSlot (startTag) {
if (startTag.parent.name !== 'template') {
return false
}

const slotAttr = startTag.attributes
.find(attr => attr.directive === false && attr.key.name === 'slot')
if (slotAttr) {
// if the element have `slot` it can not be converted.
// Conversion of `slot` is done with `vue/no-deprecated-slot-attribute`.
return false
}

const vBindSlotAttr = startTag.attributes
.find(attr =>
attr.directive === true &&
attr.key.name.name === 'bind' &&
attr.key.argument &&
attr.key.argument.name === 'slot')
if (vBindSlotAttr) {
// if the element have `v-bind:slot` it can not be converted.
// Conversion of `v-bind:slot` is done with `vue/no-deprecated-slot-attribute`.
return false
}
return true
}

/**
* Convert to `v-slot`.
* @param {object} fixer fixer
* @param {VAttribute | null} scopeAttr node of `slot-scope`
* @returns {*} fix data
*/
function fixSlotScopeToVSlot (fixer, scopeAttr) {
const scopeValue = scopeAttr && scopeAttr.value
? `=${sourceCode.getText(scopeAttr.value)}`
: ''

const replaceText = `v-slot${scopeValue}`
return fixer.replaceText(scopeAttr, replaceText)
}
/**
* Reports `slot-scope` node
* @param {VAttribute} scopeAttr node of `slot-scope`
* @returns {void}
*/
function reportSlotScope (scopeAttr) {
context.report({
node: scopeAttr.key,
messageId: 'forbiddenSlotScopeAttribute',
fix: fixToUpgrade
// fix to use `v-slot`
? (fixer) => {
const startTag = scopeAttr.parent
if (!canConvertToVSlot(startTag)) {
return null
}
return fixSlotScopeToVSlot(fixer, scopeAttr)
}
: null
})
}

return {
"VAttribute[directive=true][key.name.name='slot-scope']": reportSlotScope
}
}
}
143 changes: 143 additions & 0 deletions tests/lib/rules/no-deprecated-slot-scope-attribute.js
@@ -0,0 +1,143 @@
'use strict'

const RuleTester = require('eslint').RuleTester
const rule = require('../../../lib/rules/no-deprecated-slot-scope-attribute')

const tester = new RuleTester({
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 2015
}
})

tester.run('no-deprecated-slot-scope-attribute', rule, {
valid: [
`<template>
<LinkList>
<template v-slot:name><a /></template>
</LinkList>
</template>`,
`<template>
<LinkList>
<template #name><a /></template>
</LinkList>
</template>`,
`<template>
<LinkList>
<template v-slot="{a}"><a /></template>
</LinkList>
</template>`,
`<template>
<LinkList v-slot="{a}">
<a />
</LinkList>
</template>`,
`<template>
<LinkList>
<template #default="{a}"><a /></template>
</LinkList>
</template>`,
`<template>
<LinkList>
<a slot="name" />
</LinkList>
</template>`,
`<template>
<LinkList>
<template><a /></template>
</LinkList>
</template>`,
`<template>
<LinkList>
<a />
</LinkList>`
],
invalid: [
{
code: `
<template>
<LinkList>
<template slot-scope="{a}"><a /></template>
</LinkList>
</template>`,
output: `
<template>
<LinkList>
<template v-slot="{a}"><a /></template>
</LinkList>
</template>`,
errors: [
{
message: '`slot-scope` are deprecated.',
line: 4
}
]
},
{
code: `
<template>
<LinkList>
<template slot-scope><a /></template>
</LinkList>
</template>`,
output: `
<template>
<LinkList>
<template v-slot><a /></template>
</LinkList>
</template>`,
errors: [
{
message: '`slot-scope` are deprecated.',
line: 4
}
]
},
// cannot fix
{
code: `
<template>
<LinkList>
<a slot-scope="{a}" />
</LinkList>
</template>`,
output: null,
errors: [
{
message: '`slot-scope` are deprecated.',
line: 4
}
]
},
{
code: `
<template>
<LinkList>
<template slot-scope="{a}" slot="foo"><a /></template>
</LinkList>
</template>`,
output: null,
errors: [
{
message: '`slot-scope` are deprecated.',
line: 4
}
]
},
{
code: `
<template>
<LinkList>
<template slot-scope="{a}" :slot="arg"><a /></template>
</LinkList>
</template>`,
output: null,
errors: [
{
message: '`slot-scope` are deprecated.',
line: 4
}
]
}
]
})

0 comments on commit a5fd31e

Please sign in to comment.