Skip to content

Commit

Permalink
Support Nuxt.js's asyncData in various rules (#1679)
Browse files Browse the repository at this point in the history
* Support `asyncData` in `vue/no-undef-properties`

* Support `asyncData` in `vue/no-dupe-keys`

* Support `asyncData` in `vue/no-reserved-keys`

* Support `asyncData` in `vue/no-template-shadow`

* Support `asyncData` in `vue/no-unused-properties`

* Lint
  • Loading branch information
FloEdelmann committed Oct 29, 2021
1 parent 44ff0e0 commit 0437972
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 8 deletions.
9 changes: 8 additions & 1 deletion lib/rules/no-dupe-keys.js
Expand Up @@ -14,7 +14,14 @@ const utils = require('../utils')
// Rule Definition
// ------------------------------------------------------------------------------
/** @type {GroupName[]} */
const GROUP_NAMES = ['props', 'computed', 'data', 'methods', 'setup']
const GROUP_NAMES = [
'props',
'computed',
'data',
'asyncData',
'methods',
'setup'
]

module.exports = {
meta: {
Expand Down
14 changes: 12 additions & 2 deletions lib/rules/no-reserved-keys.js
Expand Up @@ -16,7 +16,14 @@ const utils = require('../utils')

const RESERVED_KEYS = require('../utils/vue-reserved.json')
/** @type {GroupName[]} */
const GROUP_NAMES = ['props', 'computed', 'data', 'methods', 'setup']
const GROUP_NAMES = [
'props',
'computed',
'data',
'asyncData',
'methods',
'setup'
]

module.exports = {
meta: {
Expand Down Expand Up @@ -76,7 +83,10 @@ module.exports = {
utils.executeOnVue(context, (obj) => {
const properties = utils.iterateProperties(obj, groups)
for (const o of properties) {
if (o.groupName === 'data' && o.name[0] === '_') {
if (
(o.groupName === 'data' || o.groupName === 'asyncData') &&
o.name[0] === '_'
) {
context.report({
node: o.node,
messageId: 'startsWithUnderscore',
Expand Down
9 changes: 8 additions & 1 deletion lib/rules/no-template-shadow.js
Expand Up @@ -19,7 +19,14 @@ const utils = require('../utils')
// ------------------------------------------------------------------------------

/** @type {GroupName[]} */
const GROUP_NAMES = ['props', 'computed', 'data', 'methods', 'setup']
const GROUP_NAMES = [
'props',
'computed',
'data',
'asyncData',
'methods',
'setup'
]

module.exports = {
meta: {
Expand Down
5 changes: 4 additions & 1 deletion lib/rules/no-undef-properties.js
Expand Up @@ -32,6 +32,7 @@ const {
// ------------------------------------------------------------------------------

const GROUP_PROPERTY = 'props'
const GROUP_ASYNC_DATA = 'asyncData' // Nuxt.js
const GROUP_DATA = 'data'
const GROUP_COMPUTED_PROPERTY = 'computed'
const GROUP_METHODS = 'methods'
Expand Down Expand Up @@ -334,6 +335,7 @@ module.exports = {
node,
new Set([
GROUP_PROPERTY,
GROUP_ASYNC_DATA,
GROUP_DATA,
GROUP_COMPUTED_PROPERTY,
GROUP_SETUP,
Expand All @@ -342,7 +344,8 @@ module.exports = {
])
)) {
const propertyMap =
prop.groupName === GROUP_DATA &&
(prop.groupName === GROUP_DATA ||
prop.groupName === GROUP_ASYNC_DATA) &&
prop.type === 'object' &&
prop.property.value.type === 'ObjectExpression'
? getObjectPropertyMap(prop.property.value)
Expand Down
6 changes: 5 additions & 1 deletion lib/rules/no-unused-properties.js
Expand Up @@ -55,6 +55,7 @@ const {

const GROUP_PROPERTY = 'props'
const GROUP_DATA = 'data'
const GROUP_ASYNC_DATA = 'asyncData'
const GROUP_COMPUTED_PROPERTY = 'computed'
const GROUP_METHODS = 'methods'
const GROUP_SETUP = 'setup'
Expand All @@ -64,6 +65,7 @@ const GROUP_EXPOSE = 'expose'
const PROPERTY_LABEL = {
props: 'property',
data: 'data',
asyncData: 'async data',
computed: 'computed property',
methods: 'method',
setup: 'property returned from `setup()`',
Expand Down Expand Up @@ -213,6 +215,7 @@ module.exports = {
enum: [
GROUP_PROPERTY,
GROUP_DATA,
GROUP_ASYNC_DATA,
GROUP_COMPUTED_PROPERTY,
GROUP_METHODS,
GROUP_SETUP
Expand Down Expand Up @@ -350,7 +353,8 @@ module.exports = {
// used
if (
deepData &&
property.groupName === 'data' &&
(property.groupName === 'data' ||
property.groupName === 'asyncData') &&
property.type === 'object'
) {
// Check the deep properties of the data option.
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/index.js
Expand Up @@ -23,7 +23,7 @@
* @typedef { {key: string | null, value: BlockStatement | null} } ComponentComputedProperty
*/
/**
* @typedef { 'props' | 'data' | 'computed' | 'setup' | 'watch' | 'methods' | 'provide' | 'inject' | 'expose' } GroupName
* @typedef { 'props' | 'asyncData' | 'data' | 'computed' | 'setup' | 'watch' | 'methods' | 'provide' | 'inject' | 'expose' } GroupName
* @typedef { { type: 'array', name: string, groupName: GroupName, node: Literal | TemplateLiteral } } ComponentArrayPropertyData
* @typedef { { type: 'object', name: string, groupName: GroupName, node: Identifier | Literal | TemplateLiteral, property: Property } } ComponentObjectPropertyData
* @typedef { ComponentArrayPropertyData | ComponentObjectPropertyData } ComponentPropertyData
Expand Down
23 changes: 23 additions & 0 deletions tests/lib/rules/no-dupe-keys.js
Expand Up @@ -709,6 +709,29 @@ ruleTester.run('no-dupe-keys', rule, {
}
]
},
{
filename: 'test.vue',
code: `
export default {
asyncData() {
return {
foo: 1
}
},
data() {
return {
foo: 2
}
},
}
`,
errors: [
{
message: "Duplicated key 'foo'.",
line: 10
}
]
},
{
filename: 'test.js',
code: `
Expand Down
36 changes: 36 additions & 0 deletions tests/lib/rules/no-reserved-keys.js
Expand Up @@ -156,6 +156,25 @@ ruleTester.run('no-reserved-keys', rule, {
}
]
},
{
filename: 'test.js',
code: `
new Vue({
asyncData () {
return {
$el: ''
}
}
})
`,
parserOptions: { ecmaVersion: 6 },
errors: [
{
message: "Key '$el' is reserved.",
line: 5
}
]
},
{
filename: 'test.js',
code: `
Expand Down Expand Up @@ -209,6 +228,23 @@ ruleTester.run('no-reserved-keys', rule, {
}
]
},
{
filename: 'test.js',
code: `
new Vue({
asyncData: () => ({
_foo: String
})
})
`,
parserOptions: { ecmaVersion: 6 },
errors: [
{
message: "Keys starting with '_' are reserved in '_foo' group.",
line: 4
}
]
},
{
filename: 'test.js',
code: `
Expand Down
22 changes: 22 additions & 0 deletions tests/lib/rules/no-template-shadow.js
Expand Up @@ -250,6 +250,28 @@ ruleTester.run('no-template-shadow', rule, {
}
]
},
{
filename: 'test.vue',
code: `<template>
<div v-for="i in 5"></div>
</template>
<script>
export default {
asyncData() {
return {
i: 27,
}
}
}
</script>`,
errors: [
{
message: "Variable 'i' is already declared in the upper scope.",
type: 'Identifier',
line: 2
}
]
},
{
filename: 'test.vue',
code: `<template>
Expand Down
17 changes: 17 additions & 0 deletions tests/lib/rules/no-undef-properties.js
Expand Up @@ -67,6 +67,23 @@ tester.run('no-undef-properties', rule, {
</script>
`
},
{
filename: 'test.vue',
code: `
<template>
<div> {{ foo }} </div>
</template>
<script>
export default {
asyncData() {
return {
foo: 42
}
},
};
</script>
`
},
//default ignores
{
filename: 'test.vue',
Expand Down
48 changes: 47 additions & 1 deletion tests/lib/rules/no-unused-properties.js
Expand Up @@ -16,7 +16,7 @@ const tester = new RuleTester({
})

const allOptions = [
{ groups: ['props', 'computed', 'data', 'methods', 'setup'] }
{ groups: ['props', 'computed', 'data', 'asyncData', 'methods', 'setup'] }
]
const deepDataOptions = [{ groups: ['data'], deepData: true }]

Expand Down Expand Up @@ -647,6 +647,26 @@ tester.run('no-unused-properties', rule, {
options: allOptions
},

// async data passed in a component
{
filename: 'test.vue',
code: `
<template>
<counter :count="foo" />
</template>
<script>
export default {
asyncData() {
return {
foo: 2
}
}
}
</script>
`,
options: allOptions
},

// ignores unused data when marked with eslint-disable
{
filename: 'test.vue',
Expand Down Expand Up @@ -1709,6 +1729,32 @@ tester.run('no-unused-properties', rule, {
]
},

// unused async data
{
filename: 'test.vue',
code: `
<template>
<div>{{ cont }}</div>
</template>
<script>
export default {
asyncData () {
return {
count: 2
};
}
};
</script>
`,
options: [{ groups: ['props', 'computed', 'data', 'asyncData'] }],
errors: [
{
message: "'count' of async data found, but never used.",
line: 9
}
]
},

// unused computed property
{
filename: 'test.vue',
Expand Down

0 comments on commit 0437972

Please sign in to comment.