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

New: add no-use-computed-property-like-method rules #1234

Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b14d0f3
chore: init rule
tyankatsu0105 Jul 7, 2020
6b0b860
feat: getable methodProperties
tyankatsu0105 Oct 10, 2020
4d8ae20
feat: move getMethodProperties into util
tyankatsu0105 Oct 10, 2020
7aaf02d
feat: pass rule
tyankatsu0105 Oct 10, 2020
f5c426c
feat: remove getMethodProperties
tyankatsu0105 Oct 10, 2020
e97c749
docs: add docs
tyankatsu0105 Oct 10, 2020
c61acae
chore: run update
tyankatsu0105 Oct 10, 2020
587d808
feat: check return type of data props methods computed
tyankatsu0105 Nov 13, 2020
f460c6f
feat: add types to eslint utils getStaticValue
tyankatsu0105 Nov 13, 2020
969120a
feat: refactor rule
tyankatsu0105 Nov 14, 2020
7ce7a03
docs: fix docs
tyankatsu0105 Nov 14, 2020
cc7cde4
docs: fix docs
tyankatsu0105 Nov 14, 2020
62b82be
feat: change report node
tyankatsu0105 Nov 14, 2020
c614b6d
chore: remove unused file
tyankatsu0105 Nov 14, 2020
13eff80
refactor: improve JSDoc
tyankatsu0105 Nov 14, 2020
01c4f84
docs: remove template
tyankatsu0105 Nov 14, 2020
9c54158
docs: fix docs
tyankatsu0105 Nov 14, 2020
00dc589
docs: fix docs
tyankatsu0105 Nov 14, 2020
78c203d
feat: change target node
tyankatsu0105 Nov 14, 2020
96fecb1
feat: rename getComponentPropsType
tyankatsu0105 Dec 4, 2020
3edce05
Merge branch 'master' into feat/add-no-use-computed-property-like-method
tyankatsu0105 May 1, 2021
330d188
rename eslint
tyankatsu0105 May 2, 2021
11b7ef1
refactor: rename PropertyMap
tyankatsu0105 May 2, 2021
8b825e5
refactor: improve if statement
tyankatsu0105 May 2, 2021
2e316f8
Revert "refactor: improve if statement"
tyankatsu0105 May 2, 2021
d8a8af9
feat: consider basic props type
tyankatsu0105 May 2, 2021
986648b
chore: run update
tyankatsu0105 May 2, 2021
b06421b
refactor improve selector
tyankatsu0105 May 2, 2021
7459eea
feat: addPropertyMap
tyankatsu0105 May 2, 2021
d885a36
refactor: use findProperty
tyankatsu0105 May 3, 2021
ccbee98
refactor: add comment
tyankatsu0105 May 3, 2021
c2bc020
feat: cover ThisExpression
tyankatsu0105 May 3, 2021
c082183
Merge branch 'master' into feat/add-no-use-computed-property-like-method
tyankatsu0105 Jul 17, 2021
3b77c4e
feat: support return statement return nothing
tyankatsu0105 Jul 17, 2021
ce93fa6
fix: support undefined of propertyMap[thisMember]
tyankatsu0105 Jul 17, 2021
60e7c48
style: run lint
tyankatsu0105 Jul 17, 2021
7cb18fe
test: add test case
tyankatsu0105 Jul 17, 2021
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
1 change: 1 addition & 0 deletions .tool-versions
@@ -0,0 +1 @@
nodejs 12.18.0
1 change: 1 addition & 0 deletions docs/rules/README.md
Expand Up @@ -308,6 +308,7 @@ For example:
| [vue/no-unregistered-components](./no-unregistered-components.md) | disallow using components that are not registered inside templates | |
| [vue/no-unsupported-features](./no-unsupported-features.md) | disallow unsupported Vue.js syntax on the specified version | :wrench: |
| [vue/no-unused-properties](./no-unused-properties.md) | disallow unused properties | |
| [vue/no-use-computed-property-like-method](./no-use-computed-property-like-method.md) | disallow use computed property like method | |
| [vue/no-useless-mustaches](./no-useless-mustaches.md) | disallow unnecessary mustache interpolations | :wrench: |
| [vue/no-useless-v-bind](./no-useless-v-bind.md) | disallow unnecessary `v-bind` directives | :wrench: |
| [vue/padding-line-between-blocks](./padding-line-between-blocks.md) | require or disallow padding lines between blocks | :wrench: |
Expand Down
55 changes: 55 additions & 0 deletions docs/rules/no-use-computed-property-like-method.md
@@ -0,0 +1,55 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/no-use-computed-property-like-method
description: disallow use computed property like method
---
# vue/no-use-computed-property-like-method
> disallow use computed property like method

## :book: Rule Details

This rule disallows to use computed property like method.

<eslint-code-block :rules="{'vue/no-use-computed-property-like-method': ['error']}">

```vue
<template>
<div>
</div>
</template>

<script>
export default {
props: {
name: {
type: String
},
},
computed: {
isExpectedName() {
return this.name === 'name';
}
},
methods: {
getName() {
return this.isExpectedName
},
getNameCallLikeMethod() {
return this.isExpectedName()
}
}
}
</script>
```

</eslint-code-block>

## :wrench: Options

Nothing.

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-use-computed-property-like-method.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-use-computed-property-like-method.js)
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -107,6 +107,7 @@ module.exports = {
'no-unused-components': require('./rules/no-unused-components'),
'no-unused-properties': require('./rules/no-unused-properties'),
'no-unused-vars': require('./rules/no-unused-vars'),
'no-use-computed-property-like-method': require('./rules/no-use-computed-property-like-method'),
'no-use-v-if-with-v-for': require('./rules/no-use-v-if-with-v-for'),
'no-useless-concat': require('./rules/no-useless-concat'),
'no-useless-mustaches': require('./rules/no-useless-mustaches'),
Expand Down
74 changes: 74 additions & 0 deletions lib/rules/no-use-computed-property-like-method.js
@@ -0,0 +1,74 @@
/**
* @author tyankatsu <https://github.com/tyankatsu0105>
* See LICENSE file in root directory for full license.
*/
'use strict'

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

const { defineVueVisitor, getComputedProperties } = require('../utils')

/**
* @typedef {import('../utils').ComponentComputedProperty} ComponentComputedProperty
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
*/

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'disallow use computed property like method',
categories: undefined,
url:
'https://eslint.vuejs.org/rules/no-use-computed-property-like-method.html'
},
fixable: null,
schema: [],
messages: {
unexpected: 'Does not allow to use computed with this expression.'
}
},
/** @param {RuleContext} context */
create(context) {
/**
* @typedef {object} ScopeStack
* @property {ScopeStack | null} upper
* @property {BlockStatement | Expression} body
*/
/** @type {Map<ObjectExpression, ComponentComputedProperty[]>} */
const computedPropertiesMap = new Map()

return defineVueVisitor(context, {
onVueObjectEnter(node) {
computedPropertiesMap.set(node, getComputedProperties(node))
ota-meshi marked this conversation as resolved.
Show resolved Hide resolved
},

/** @param {MemberExpression} node */
'MemberExpression[object.type="ThisExpression"]'(
node,
{ node: vueNode }
) {
if (node.property.type !== 'Identifier') return
if (node.parent.type !== 'CallExpression') return

const computedProperties = computedPropertiesMap
.get(vueNode)
.map((item) => item.key)

if (!computedProperties.includes(node.property.name)) return

context.report({
node: node.property,
loc: node.property.loc,
messageId: 'unexpected'
})
}
})
}
}
137 changes: 137 additions & 0 deletions tests/lib/rules/no-use-computed-property-like-method.js
@@ -0,0 +1,137 @@
/**
* @author tyankatsu <https://github.com/tyankatsu0105>
* See LICENSE file in root directory for full license.
*/

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

const RuleTester = require('eslint').RuleTester
const rule = require('../../../lib/rules/no-use-computed-property-like-method')

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

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

tester.run('no-use-computed-property-like-method', rule, {
valid: [
{
filename: 'test.vue',
code: `
<script>
export default {
computed: {
name() {
return 'name';
}
},
methods: {
getName() {
return this.name
}
},
}
</script>
`
},
{
filename: 'test.vue',
code: `
<script>
export default {
props: {
name: {
type: String
},
},
computed: {
isExpectedName() {
return this.name === 'name';
}
},
methods: {
getName() {
return this.isExpectedName
}
},
}
</script>
`
},
{
filename: 'test.vue',
code: `
<script>
export default {
computed: {
name() {
return 'name';
},
isExpectedName() {
return this.name === 'name';
}
},
methods: {
getName() {
return this.isExpectedName
}
},
}
</script>
`
}
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have found an error in some cases. Could you add the following test cases?

<script>
export default {
  computed: {
    bar() {
      return
    }
  }
}
</script>
<script>
export default {
  methods: {
    fn() {
      this.foo()
    }
  }
}
</script>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
I'll do that :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ota-meshi
I changed some codes to support the above cases.
3b77c4e
ce93fa6

However, I will not support this case:

<script>
export default {
  methods: {
    fn() {
      this.foo()
    }
  }
}
</script>

Because this rule only checkes whether computed properties are expected as property or not.
In this case, computed is not used.

Copy link
Member

@ota-meshi ota-meshi Jul 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want support. I've found that using a rule in that source code reports a crash or an incorrect error, so I just want to add test cases to tests if it's okay.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.
I just make sense of what you said :)
I added test case
7cb18fe

invalid: [
{
filename: 'test.vue',
code: `
<script>
export default {
computed: {
name() {
return 'name';
}
},
methods: {
getName() {
return this.name()
}
}
}
</script>
`,
errors: ['Does not allow to use computed with this expression.']
},
{
filename: 'test.vue',
code: `
<script>
export default {
props: {
name: {
type: String
},
},
computed: {
isExpectedName() {
return this.name === 'name';
}
},
methods: {
getName() {
return this.isExpectedName()
}
}
}
</script>
`,
errors: ['Does not allow to use computed with this expression.']
}
]
})