From b14d0f314cb57455b509ad57fe2349d22740885b Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Tue, 7 Jul 2020 23:10:00 +0900 Subject: [PATCH 01/35] chore: init rule --- docs/rules/no-use-computed-property-like-method.md | 6 ++++++ lib/rules/no-use-computed-property-like-method.js | 4 ++++ tests/lib/rules/no-use-computed-property-like-method.js | 4 ++++ 3 files changed, 14 insertions(+) create mode 100644 docs/rules/no-use-computed-property-like-method.md create mode 100644 lib/rules/no-use-computed-property-like-method.js create mode 100644 tests/lib/rules/no-use-computed-property-like-method.js diff --git a/docs/rules/no-use-computed-property-like-method.md b/docs/rules/no-use-computed-property-like-method.md new file mode 100644 index 000000000..08b64382b --- /dev/null +++ b/docs/rules/no-use-computed-property-like-method.md @@ -0,0 +1,6 @@ +--- +pageClass: rule-details +sidebarDepth: 0 +title: vue/no-use-computed-property-like-method +description: disallow use computed properties like methods +--- diff --git a/lib/rules/no-use-computed-property-like-method.js b/lib/rules/no-use-computed-property-like-method.js new file mode 100644 index 000000000..fdefaf422 --- /dev/null +++ b/lib/rules/no-use-computed-property-like-method.js @@ -0,0 +1,4 @@ +/** + * @author tyankatsu + * See LICENSE file in root directory for full license. + */ diff --git a/tests/lib/rules/no-use-computed-property-like-method.js b/tests/lib/rules/no-use-computed-property-like-method.js new file mode 100644 index 000000000..fdefaf422 --- /dev/null +++ b/tests/lib/rules/no-use-computed-property-like-method.js @@ -0,0 +1,4 @@ +/** + * @author tyankatsu + * See LICENSE file in root directory for full license. + */ From 6b0b8609d92fd361240d1fb2e76f92b1beb59b17 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Sat, 10 Oct 2020 10:17:18 +0900 Subject: [PATCH 02/35] feat: getable methodProperties --- .tool-versions | 1 + .../no-use-computed-property-like-method.js | 186 ++++++++++++++++++ .../no-use-computed-property-like-method.js | 131 ++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 .tool-versions diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 000000000..dfaa2aed4 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +nodejs 12.18.0 diff --git a/lib/rules/no-use-computed-property-like-method.js b/lib/rules/no-use-computed-property-like-method.js index fdefaf422..82761dd3b 100644 --- a/lib/rules/no-use-computed-property-like-method.js +++ b/lib/rules/no-use-computed-property-like-method.js @@ -2,3 +2,189 @@ * @author tyankatsu * See LICENSE file in root directory for full license. */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const { + defineVueVisitor, + getComputedProperties, + getComponentProps, + + isProperty, + getStaticPropertyName, + unwrapTypes +} = require('../utils') + +/** + * @typedef {import('../utils').ComponentComputedProperty} ComponentComputedProperty + * @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp + */ + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +/** + * @typedef { {key: string | null, value: BlockStatement | null} } ComponentMethodProperty + */ + +/** + * Get all method by looking at all component's properties + * @param {ObjectExpression} componentObject Object with component definition + * @return {ComponentMethodProperty[]} Array of methods in format: [{key: String, value: ASTNode}] + */ +const getMethodProperties = (componentObject) => { + const methodsNode = componentObject.properties.find( + /** + * @param {ESNode} property + * @returns {property is (Property & { key: Identifier & {name: 'method'}, value: ObjectExpression })} + */ + (property) => { + return ( + property.type === 'Property' && + property.key.type === 'Identifier' && + property.key.name === 'methods' && + property.value.type === 'ObjectExpression' + ) + } + ) + + if (!methodsNode) { + return [] + } + + return methodsNode.value.properties.filter(isProperty).map((method) => { + const key = getStaticPropertyName(method) + /** @type {Expression} */ + const propValue = unwrapTypes(method.value) + /** @type {BlockStatement | null} */ + let value = null + + if (propValue.type === 'FunctionExpression') { + value = propValue.body + } else if (propValue.type === 'ObjectExpression') { + const get = propValue.properties.find( + /** + * @param {ESNode} p + * @returns { p is (Property & { value: FunctionExpression }) } + */ + (p) => + p.type === 'Property' && + p.key.type === 'Identifier' && + p.key.name === 'get' && + p.value.type === 'FunctionExpression' + ) + value = get ? get.value.body : null + } + + return { key, value } + }) +} + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'enforce', + categories: undefined, + url: + 'https://eslint.vuejs.org/rules/no-use-computed-property-like-method.html' + }, + fixable: null, + schema: [], + messages: { + unexpected: 'Unexpected multiple objects. Merge objects.' + } + }, + /** @param {RuleContext} context */ + create(context) { + /** + * @typedef {object} ScopeStack + * @property {ScopeStack | null} upper + * @property {BlockStatement | Expression} body + */ + /** @type {Map} */ + const computedPropertiesMap = new Map() + + /** + * @typedef {object} ScopeStack + * @property {ScopeStack | null} upper + * @property {BlockStatement | Expression} body + */ + /** @type {Map} */ + const propsMap = new Map() + + /** + * @typedef {object} ScopeStack + * @property {ScopeStack | null} upper + * @property {BlockStatement | Expression} body + */ + /** @type {Map} */ + const methodPropertiesMap = new Map() + return defineVueVisitor(context, { + onVueObjectEnter(node) { + computedPropertiesMap.set(node, getComputedProperties(node)) + propsMap.set(node, getComponentProps(node)) + methodPropertiesMap.set(node, getMethodProperties(node)) + }, + + /** @param {MemberExpression} node */ + 'MemberExpression[object.type="ThisExpression"]'( + node, + { node: vueNode } + ) { + if (node.property.type !== 'Identifier') return + + const computedProperties = computedPropertiesMap + .get(vueNode) + .map((item) => item.key) + + const methodProperties = methodPropertiesMap + .get(vueNode) + .map((item) => item.key) + + /** + * propsProperties that excluded when type is array, and props property type is `Function` + */ + const propsProperties = propsMap.get(vueNode).reduce((acc, current) => { + // ignore `props: ['props1', 'props2']` + if (current.type === 'array') return acc + + current.value.properties.reduce((accProperties, property) => { + // ignore `type: Function` + if ( + property.key.name === 'type' && + property.value.name === 'Function' + ) + return accProperties + + accProperties.push(property) + return accProperties + }, []) + + acc.push(current.propName) + return acc + }, []) + + const properties = [ + ...computedProperties, + ...methodProperties, + ...propsProperties + ] + + console.log(properties) + + // if (!computedProperties.includes(node.property.name)) return + + // context.report({ + // node: node.property, + // loc: node.property.loc, + // messageId: + // }) + } + }) + } +} diff --git a/tests/lib/rules/no-use-computed-property-like-method.js b/tests/lib/rules/no-use-computed-property-like-method.js index fdefaf422..8b153c1ca 100644 --- a/tests/lib/rules/no-use-computed-property-like-method.js +++ b/tests/lib/rules/no-use-computed-property-like-method.js @@ -2,3 +2,134 @@ * @author tyankatsu * 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: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + } + ], + invalid: [ + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + } + ] +}) From 4d8ae20d43a9b85d13bccd7b7b86b907f09949f5 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Sat, 10 Oct 2020 10:29:25 +0900 Subject: [PATCH 03/35] feat: move getMethodProperties into util --- .../no-use-computed-property-like-method.js | 62 +------------------ lib/utils/index.js | 56 +++++++++++++++++ 2 files changed, 57 insertions(+), 61 deletions(-) diff --git a/lib/rules/no-use-computed-property-like-method.js b/lib/rules/no-use-computed-property-like-method.js index 82761dd3b..c5d08a787 100644 --- a/lib/rules/no-use-computed-property-like-method.js +++ b/lib/rules/no-use-computed-property-like-method.js @@ -12,10 +12,7 @@ const { defineVueVisitor, getComputedProperties, getComponentProps, - - isProperty, - getStaticPropertyName, - unwrapTypes + getMethodProperties } = require('../utils') /** @@ -27,63 +24,6 @@ const { // Rule Definition // ------------------------------------------------------------------------------ -/** - * @typedef { {key: string | null, value: BlockStatement | null} } ComponentMethodProperty - */ - -/** - * Get all method by looking at all component's properties - * @param {ObjectExpression} componentObject Object with component definition - * @return {ComponentMethodProperty[]} Array of methods in format: [{key: String, value: ASTNode}] - */ -const getMethodProperties = (componentObject) => { - const methodsNode = componentObject.properties.find( - /** - * @param {ESNode} property - * @returns {property is (Property & { key: Identifier & {name: 'method'}, value: ObjectExpression })} - */ - (property) => { - return ( - property.type === 'Property' && - property.key.type === 'Identifier' && - property.key.name === 'methods' && - property.value.type === 'ObjectExpression' - ) - } - ) - - if (!methodsNode) { - return [] - } - - return methodsNode.value.properties.filter(isProperty).map((method) => { - const key = getStaticPropertyName(method) - /** @type {Expression} */ - const propValue = unwrapTypes(method.value) - /** @type {BlockStatement | null} */ - let value = null - - if (propValue.type === 'FunctionExpression') { - value = propValue.body - } else if (propValue.type === 'ObjectExpression') { - const get = propValue.properties.find( - /** - * @param {ESNode} p - * @returns { p is (Property & { value: FunctionExpression }) } - */ - (p) => - p.type === 'Property' && - p.key.type === 'Identifier' && - p.key.name === 'get' && - p.value.type === 'FunctionExpression' - ) - value = get ? get.value.body : null - } - - return { key, value } - }) -} - module.exports = { meta: { type: 'problem', diff --git a/lib/utils/index.js b/lib/utils/index.js index 814517e39..6278ddc4f 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -80,6 +80,9 @@ /** * @typedef { {key: string | null, value: BlockStatement | null} } ComponentComputedProperty */ +/** + * @typedef { {key: string | null, value: BlockStatement | null} } ComponentMethodProperty + */ /** * @typedef { 'props' | 'data' | 'computed' | 'setup' | 'watch' | 'methods' } GroupName * @typedef { { type: 'array', name: string, groupName: GroupName, node: Literal | TemplateLiteral } } ComponentArrayPropertyData @@ -845,6 +848,59 @@ module.exports = { }) }, + /** + * Get all method by looking at all component's properties + * @param {ObjectExpression} componentObject Object with component definition + * @return {ComponentMethodProperty[]} Array of methods in format: [{key: String, value: ASTNode}] + */ + getMethodProperties(componentObject) { + const methodsNode = componentObject.properties.find( + /** + * @param {ESNode} property + * @returns {property is (Property & { key: Identifier & {name: 'method'}, value: ObjectExpression })} + */ + (property) => { + return ( + property.type === 'Property' && + property.key.type === 'Identifier' && + property.key.name === 'methods' && + property.value.type === 'ObjectExpression' + ) + } + ) + + if (!methodsNode) { + return [] + } + + return methodsNode.value.properties.filter(isProperty).map((method) => { + const key = getStaticPropertyName(method) + /** @type {Expression} */ + const propValue = skipTSAsExpression(method.value) + /** @type {BlockStatement | null} */ + let value = null + + if (propValue.type === 'FunctionExpression') { + value = propValue.body + } else if (propValue.type === 'ObjectExpression') { + const get = propValue.properties.find( + /** + * @param {ESNode} p + * @returns { p is (Property & { value: FunctionExpression }) } + */ + (p) => + p.type === 'Property' && + p.key.type === 'Identifier' && + p.key.name === 'get' && + p.value.type === 'FunctionExpression' + ) + value = get ? get.value.body : null + } + + return { key, value } + }) + }, + isVueFile, /** From 7aaf02d763e0b42b6641852acd9be1ab679a54a1 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Sat, 10 Oct 2020 11:35:44 +0900 Subject: [PATCH 04/35] feat: pass rule --- .../no-use-computed-property-like-method.js | 23 +++++++------------ .../no-use-computed-property-like-method.js | 6 +++-- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/lib/rules/no-use-computed-property-like-method.js b/lib/rules/no-use-computed-property-like-method.js index c5d08a787..2e343fc5b 100644 --- a/lib/rules/no-use-computed-property-like-method.js +++ b/lib/rules/no-use-computed-property-like-method.js @@ -36,7 +36,7 @@ module.exports = { fixable: null, schema: [], messages: { - unexpected: 'Unexpected multiple objects. Merge objects.' + unexpected: 'Does not allow to use computed with this expression.' } }, /** @param {RuleContext} context */ @@ -77,6 +77,7 @@ module.exports = { { node: vueNode } ) { if (node.property.type !== 'Identifier') return + if (node.parent.type !== 'CallExpression') return const computedProperties = computedPropertiesMap .get(vueNode) @@ -109,21 +110,13 @@ module.exports = { return acc }, []) - const properties = [ - ...computedProperties, - ...methodProperties, - ...propsProperties - ] + if (!computedProperties.includes(node.property.name)) return - console.log(properties) - - // if (!computedProperties.includes(node.property.name)) return - - // context.report({ - // node: node.property, - // loc: node.property.loc, - // messageId: - // }) + context.report({ + node: node.property, + loc: node.property.loc, + messageId: 'unexpected' + }) } }) } diff --git a/tests/lib/rules/no-use-computed-property-like-method.js b/tests/lib/rules/no-use-computed-property-like-method.js index 8b153c1ca..f1a928dda 100644 --- a/tests/lib/rules/no-use-computed-property-like-method.js +++ b/tests/lib/rules/no-use-computed-property-like-method.js @@ -105,7 +105,8 @@ tester.run('no-use-computed-property-like-method', rule, { } } - ` + `, + errors: ['Does not allow to use computed with this expression.'] }, { filename: 'test.vue', @@ -129,7 +130,8 @@ tester.run('no-use-computed-property-like-method', rule, { } } - ` + `, + errors: ['Does not allow to use computed with this expression.'] } ] }) From f5c426c39a16fa3f71a00d51420af06643383cd7 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Sat, 10 Oct 2020 11:38:01 +0900 Subject: [PATCH 05/35] feat: remove getMethodProperties --- .../no-use-computed-property-like-method.js | 51 +---------------- lib/utils/index.js | 56 ------------------- 2 files changed, 1 insertion(+), 106 deletions(-) diff --git a/lib/rules/no-use-computed-property-like-method.js b/lib/rules/no-use-computed-property-like-method.js index 2e343fc5b..166451a47 100644 --- a/lib/rules/no-use-computed-property-like-method.js +++ b/lib/rules/no-use-computed-property-like-method.js @@ -8,12 +8,7 @@ // Requirements // ------------------------------------------------------------------------------ -const { - defineVueVisitor, - getComputedProperties, - getComponentProps, - getMethodProperties -} = require('../utils') +const { defineVueVisitor, getComputedProperties } = require('../utils') /** * @typedef {import('../utils').ComponentComputedProperty} ComponentComputedProperty @@ -49,26 +44,9 @@ module.exports = { /** @type {Map} */ const computedPropertiesMap = new Map() - /** - * @typedef {object} ScopeStack - * @property {ScopeStack | null} upper - * @property {BlockStatement | Expression} body - */ - /** @type {Map} */ - const propsMap = new Map() - - /** - * @typedef {object} ScopeStack - * @property {ScopeStack | null} upper - * @property {BlockStatement | Expression} body - */ - /** @type {Map} */ - const methodPropertiesMap = new Map() return defineVueVisitor(context, { onVueObjectEnter(node) { computedPropertiesMap.set(node, getComputedProperties(node)) - propsMap.set(node, getComponentProps(node)) - methodPropertiesMap.set(node, getMethodProperties(node)) }, /** @param {MemberExpression} node */ @@ -83,33 +61,6 @@ module.exports = { .get(vueNode) .map((item) => item.key) - const methodProperties = methodPropertiesMap - .get(vueNode) - .map((item) => item.key) - - /** - * propsProperties that excluded when type is array, and props property type is `Function` - */ - const propsProperties = propsMap.get(vueNode).reduce((acc, current) => { - // ignore `props: ['props1', 'props2']` - if (current.type === 'array') return acc - - current.value.properties.reduce((accProperties, property) => { - // ignore `type: Function` - if ( - property.key.name === 'type' && - property.value.name === 'Function' - ) - return accProperties - - accProperties.push(property) - return accProperties - }, []) - - acc.push(current.propName) - return acc - }, []) - if (!computedProperties.includes(node.property.name)) return context.report({ diff --git a/lib/utils/index.js b/lib/utils/index.js index 6278ddc4f..814517e39 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -80,9 +80,6 @@ /** * @typedef { {key: string | null, value: BlockStatement | null} } ComponentComputedProperty */ -/** - * @typedef { {key: string | null, value: BlockStatement | null} } ComponentMethodProperty - */ /** * @typedef { 'props' | 'data' | 'computed' | 'setup' | 'watch' | 'methods' } GroupName * @typedef { { type: 'array', name: string, groupName: GroupName, node: Literal | TemplateLiteral } } ComponentArrayPropertyData @@ -848,59 +845,6 @@ module.exports = { }) }, - /** - * Get all method by looking at all component's properties - * @param {ObjectExpression} componentObject Object with component definition - * @return {ComponentMethodProperty[]} Array of methods in format: [{key: String, value: ASTNode}] - */ - getMethodProperties(componentObject) { - const methodsNode = componentObject.properties.find( - /** - * @param {ESNode} property - * @returns {property is (Property & { key: Identifier & {name: 'method'}, value: ObjectExpression })} - */ - (property) => { - return ( - property.type === 'Property' && - property.key.type === 'Identifier' && - property.key.name === 'methods' && - property.value.type === 'ObjectExpression' - ) - } - ) - - if (!methodsNode) { - return [] - } - - return methodsNode.value.properties.filter(isProperty).map((method) => { - const key = getStaticPropertyName(method) - /** @type {Expression} */ - const propValue = skipTSAsExpression(method.value) - /** @type {BlockStatement | null} */ - let value = null - - if (propValue.type === 'FunctionExpression') { - value = propValue.body - } else if (propValue.type === 'ObjectExpression') { - const get = propValue.properties.find( - /** - * @param {ESNode} p - * @returns { p is (Property & { value: FunctionExpression }) } - */ - (p) => - p.type === 'Property' && - p.key.type === 'Identifier' && - p.key.name === 'get' && - p.value.type === 'FunctionExpression' - ) - value = get ? get.value.body : null - } - - return { key, value } - }) - }, - isVueFile, /** From e97c749e4e1a2d2d778f29715f76ecb39902a352 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Sat, 10 Oct 2020 11:45:50 +0900 Subject: [PATCH 06/35] docs: add docs --- .../no-use-computed-property-like-method.md | 52 ++++++++++++++++++- .../no-use-computed-property-like-method.js | 2 +- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/docs/rules/no-use-computed-property-like-method.md b/docs/rules/no-use-computed-property-like-method.md index 08b64382b..be1cd56ff 100644 --- a/docs/rules/no-use-computed-property-like-method.md +++ b/docs/rules/no-use-computed-property-like-method.md @@ -2,5 +2,55 @@ pageClass: rule-details sidebarDepth: 0 title: vue/no-use-computed-property-like-method -description: disallow use computed properties like methods +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. + + + +```vue + + + +``` + + + +## :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) diff --git a/lib/rules/no-use-computed-property-like-method.js b/lib/rules/no-use-computed-property-like-method.js index 166451a47..42943ad9b 100644 --- a/lib/rules/no-use-computed-property-like-method.js +++ b/lib/rules/no-use-computed-property-like-method.js @@ -23,7 +23,7 @@ module.exports = { meta: { type: 'problem', docs: { - description: 'enforce', + description: 'disallow use computed property like method', categories: undefined, url: 'https://eslint.vuejs.org/rules/no-use-computed-property-like-method.html' From c61acae4acb1ed025db11a2e4195f6c497545c51 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Sat, 10 Oct 2020 11:46:28 +0900 Subject: [PATCH 07/35] chore: run update --- docs/rules/README.md | 1 + docs/rules/no-use-computed-property-like-method.md | 1 - lib/index.js | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/rules/README.md b/docs/rules/README.md index 1ffb102f8..a7aef3c2c 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -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: | diff --git a/docs/rules/no-use-computed-property-like-method.md b/docs/rules/no-use-computed-property-like-method.md index be1cd56ff..05ca91f85 100644 --- a/docs/rules/no-use-computed-property-like-method.md +++ b/docs/rules/no-use-computed-property-like-method.md @@ -4,7 +4,6 @@ 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 diff --git a/lib/index.js b/lib/index.js index eb6a42915..79a475427 100644 --- a/lib/index.js +++ b/lib/index.js @@ -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'), From 587d808eed1e199657fbf87232d6129111823033 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Fri, 13 Nov 2020 23:56:38 +0900 Subject: [PATCH 08/35] feat: check return type of data props methods computed --- .../no-use-computed-property-like-method.md | 75 +++- .../no-use-computed-property-like-method.js | 260 +++++++++++-- .../no-use-computed-property-like-method.js | 366 ++++++++++++++++-- 3 files changed, 639 insertions(+), 62 deletions(-) diff --git a/docs/rules/no-use-computed-property-like-method.md b/docs/rules/no-use-computed-property-like-method.md index 05ca91f85..078ebe78e 100644 --- a/docs/rules/no-use-computed-property-like-method.md +++ b/docs/rules/no-use-computed-property-like-method.md @@ -21,22 +21,83 @@ This rule disallows to use computed property like method. + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + ` @@ -46,20 +158,73 @@ tester.run('no-use-computed-property-like-method', rule, { + ` + }, + { + filename: 'test.vue', + code: ` + ` @@ -69,19 +234,55 @@ tester.run('no-use-computed-property-like-method', rule, { code: ` ` @@ -94,19 +295,96 @@ tester.run('no-use-computed-property-like-method', rule, { `, - errors: ['Does not allow to use computed with this expression.'] + errors: [ + 'Use this.computedReturnString instead of this.computedReturnString().', + 'Use this.computedReturnNumber instead of this.computedReturnNumber().', + 'Use this.computedReturnObject instead of this.computedReturnObject().', + 'Use this.computedReturnArray instead of this.computedReturnArray().', + 'Use this.computedReturnBoolean instead of this.computedReturnBoolean().' + ] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: [ + 'Use this.computedReturnDataString instead of this.computedReturnDataString().', + 'Use this.computedReturnDataNumber instead of this.computedReturnDataNumber().', + 'Use this.computedReturnDataObject instead of this.computedReturnDataObject().', + 'Use this.computedReturnDataArray instead of this.computedReturnDataArray().', + 'Use this.computedReturnDataBoolean instead of this.computedReturnDataBoolean().' + ] }, { filename: 'test.vue', @@ -114,24 +392,58 @@ tester.run('no-use-computed-property-like-method', rule, { `, - errors: ['Does not allow to use computed with this expression.'] + errors: [ + 'Use this.computedReturnPropsString instead of this.computedReturnPropsString().', + 'Use this.computedReturnPropsNumber instead of this.computedReturnPropsNumber().', + 'Use this.computedReturnPropsObject instead of this.computedReturnPropsObject().', + 'Use this.computedReturnPropsArray instead of this.computedReturnPropsArray().', + 'Use this.computedReturnPropsBoolean instead of this.computedReturnPropsBoolean().' + ] } ] }) From f460c6f5e2163b6aaecfedefed1564a4f4b55509 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Fri, 13 Nov 2020 23:56:58 +0900 Subject: [PATCH 09/35] feat: add types to eslint utils getStaticValue --- typings/eslint-utils/index.d.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/typings/eslint-utils/index.d.ts b/typings/eslint-utils/index.d.ts index 884fc60cd..2461179ca 100644 --- a/typings/eslint-utils/index.d.ts +++ b/typings/eslint-utils/index.d.ts @@ -7,6 +7,11 @@ export function findVariable( nameOrNode: VAST.Identifier | string ): eslint.Scope.Variable +export function getStaticValue( + node: VAST.ESNode, + initialScope?: eslint.Scope.Scope +): { value: any } | null + export function isParenthesized( num: number, node: VAST.ESNode, From 969120a8769a269ede7edbf38cb8774afaee8fd1 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Sat, 14 Nov 2020 09:53:31 +0900 Subject: [PATCH 10/35] feat: refactor rule --- .../no-use-computed-property-like-method.md | 187 +++++++++++- .../no-use-computed-property-like-method.js | 108 +++---- .../no-use-computed-property-like-method.js | 275 +++++++++++++----- 3 files changed, 421 insertions(+), 149 deletions(-) diff --git a/docs/rules/no-use-computed-property-like-method.md b/docs/rules/no-use-computed-property-like-method.md index 078ebe78e..8c5e1f14d 100644 --- a/docs/rules/no-use-computed-property-like-method.md +++ b/docs/rules/no-use-computed-property-like-method.md @@ -56,6 +56,44 @@ This rule disallows to use computed property like method. }, }, computed: { + computedReturnDataString() { + return this.dataString + }, + computedReturnDataNumber() { + return this.dataNumber + }, + computedReturnDataObject() { + return this.dataObject + }, + computedReturnDataArray() { + return this.dataArray + }, + computedReturnDataBoolean() { + return this.dataBoolean + }, + computedReturnDataFunction() { + return this.dataFunction + }, + + computedReturnPropsString() { + return this.propsString + }, + computedReturnPropsNumber() { + return this.propsNumber + }, + computedReturnPropsObject() { + return this.propsObject + }, + computedReturnPropsArray() { + return this.propsArray + }, + computedReturnPropsBoolean() { + return this.propsBoolean + }, + computedReturnPropsFunction() { + return this.propsFunction + }, + computedReturnString() { return 'computedReturnString' }, @@ -76,7 +114,24 @@ This rule disallows to use computed property like method. computedReturnFunction() { const fn = () => alert('computedReturnFunction') return fn + }, + + computedReturnMethodsReturnString() { + return this.methodsReturnString + }, + computedReturnMethodsReturnNumber() { + return this.methodsReturnNumber + }, + computedReturnMethodsReturnObject() { + return this.methodsReturnObject + }, + computedReturnMethodsReturnArray() { + return this.methodsReturnArray + }, + computedReturnMethodsReturnBoolean() { + return this.methodsReturnBoolean } + }, methods: { methodsReturnString() { @@ -97,7 +152,137 @@ This rule disallows to use computed property like method. return true }, methodsReturnFunction() { - console.log(this.dataObject.inside); + const fn = () => alert('methodsReturnFunction') + return fn + }, + + fn() { + /* Reference data */ + /* ✓ GOOD */ + this.computedReturnDataString + this.computedReturnDataNumber + this.computedReturnDataObject + this.computedReturnDataArray + this.computedReturnDataBoolean + this.computedReturnDataFunction + this.computedReturnDataFunction() + /* ✗ BAD */ + this.computedReturnDataString() + this.computedReturnDataNumber() + this.computedReturnDataObject() + this.computedReturnDataArray() + this.computedReturnDataBoolean() + + /* Reference props */ + /* ✓ GOOD */ + this.computedReturnPropsString + this.computedReturnPropsNumber + this.computedReturnPropsObject + this.computedReturnPropsArray + this.computedReturnPropsBoolean + this.computedReturnPropsFunction + this.computedReturnPropsFunction() + /* ✗ BAD */ + this.computedReturnPropsString() + this.computedReturnPropsNumber() + this.computedReturnPropsObject() + this.computedReturnPropsArray() + this.computedReturnPropsBoolean() + + /* ✓ GOOD */ + this.computedReturnString + this.computedReturnNumber + this.computedReturnObject + this.computedReturnArray + this.computedReturnBoolean + this.computedReturnFunction + this.computedReturnFunction() + /* ✗ BAD */ + this.computedReturnString() + this.computedReturnNumber() + this.computedReturnObject() + this.computedReturnArray() + this.computedReturnBoolean() + + /* Reference methods */ + /* ✓ GOOD */ + this.computedReturnMethodsReturnString + this.computedReturnMethodsReturnNumber + this.computedReturnMethodsReturnObject + this.computedReturnMethodsReturnArray + this.computedReturnMethodsReturnBoolean + this.computedReturnMethodsReturnFunction + this.computedReturnMethodsReturnFunction() + /* ✗ BAD */ + this.computedReturnMethodsReturnString() + this.computedReturnMethodsReturnNumber() + this.computedReturnMethodsReturnObject() + this.computedReturnMethodsReturnArray() + this.computedReturnMethodsReturnBoolean() + } + } + } + +``` + +This rule can't check if props is used as array: + + + +```vue + + + - ` - }, - { - filename: 'test.vue', - code: ` - - ` - }, { filename: 'test.vue', code: ` @@ -286,9 +228,7 @@ tester.run('no-use-computed-property-like-method', rule, { } ` - } - ], - invalid: [ + }, { filename: 'test.vue', code: ` @@ -315,24 +255,116 @@ tester.run('no-use-computed-property-like-method', rule, { }, methods: { fn() { - this.computedReturnString() - this.computedReturnNumber() - this.computedReturnObject() - this.computedReturnArray() - this.computedReturnBoolean() + this.computedReturnString + this.computedReturnNumber + this.computedReturnObject + this.computedReturnArray + this.computedReturnBoolean } } } - `, - errors: [ - 'Use this.computedReturnString instead of this.computedReturnString().', - 'Use this.computedReturnNumber instead of this.computedReturnNumber().', - 'Use this.computedReturnObject instead of this.computedReturnObject().', - 'Use this.computedReturnArray instead of this.computedReturnArray().', - 'Use this.computedReturnBoolean instead of this.computedReturnBoolean().' - ] + ` }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + } + ], + invalid: [ { filename: 'test.vue', code: ` @@ -444,6 +476,101 @@ tester.run('no-use-computed-property-like-method', rule, { 'Use this.computedReturnPropsArray instead of this.computedReturnPropsArray().', 'Use this.computedReturnPropsBoolean instead of this.computedReturnPropsBoolean().' ] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: [ + 'Use this.computedReturnString instead of this.computedReturnString().', + 'Use this.computedReturnNumber instead of this.computedReturnNumber().', + 'Use this.computedReturnObject instead of this.computedReturnObject().', + 'Use this.computedReturnArray instead of this.computedReturnArray().', + 'Use this.computedReturnBoolean instead of this.computedReturnBoolean().' + ] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: [ + 'Use this.computedReturnComputedReturnString instead of this.computedReturnComputedReturnString().' + ] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: [ + 'Use this.computedReturnObject instead of this.computedReturnObject().' + ] } ] }) From 7ce7a03691635429ada992a16a78430028335781 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Sat, 14 Nov 2020 09:58:06 +0900 Subject: [PATCH 11/35] docs: fix docs --- docs/rules/no-use-computed-property-like-method.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/rules/no-use-computed-property-like-method.md b/docs/rules/no-use-computed-property-like-method.md index 8c5e1f14d..73f5573bb 100644 --- a/docs/rules/no-use-computed-property-like-method.md +++ b/docs/rules/no-use-computed-property-like-method.md @@ -225,8 +225,10 @@ This rule disallows to use computed property like method. ``` -This rule can't check if props is used as array: + +This rule can't check if props is used as array: + ```vue From cc7cde45d4c4eab57bc1b4ddf7c046b61d833b74 Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Sat, 14 Nov 2020 10:05:25 +0900 Subject: [PATCH 12/35] docs: fix docs --- docs/rules/no-use-computed-property-like-method.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rules/no-use-computed-property-like-method.md b/docs/rules/no-use-computed-property-like-method.md index 73f5573bb..67c5948c9 100644 --- a/docs/rules/no-use-computed-property-like-method.md +++ b/docs/rules/no-use-computed-property-like-method.md @@ -239,14 +239,14 @@ This rule can't check if props is used as array: ``` @@ -231,56 +274,56 @@ This rule can't check if props is used as array: ```vue ``` diff --git a/lib/rules/no-use-computed-property-like-method.js b/lib/rules/no-use-computed-property-like-method.js index a135d2445..a85a55193 100644 --- a/lib/rules/no-use-computed-property-like-method.js +++ b/lib/rules/no-use-computed-property-like-method.js @@ -21,13 +21,30 @@ const utils = require('../utils') // ------------------------------------------------------------------------------ /** - * + * Get type of props item. * @param {ComponentObjectPropertyData} property * @return {string | null} + * + * @example + * props: { + * propA: String, // => String + * propB: { + * type: Number // => String + * }, + * } */ const getComponentPropsType = (property) => { + /** + * Check basic props `props: { basicProps: ... }` + */ + if (property.property.value.type === 'Identifier') { + return property.property.value.name + } + /** + * Check object props `props: { objectProps: {...} }` + */ if (property.property.value.type === 'ObjectExpression') { - const propsTypeProperty = property.property.value.properties.find( + const propsIncludeTypeProperty = property.property.value.properties.find( (property) => property.type === 'Property' && property.key.type === 'Identifier' && @@ -35,13 +52,13 @@ const getComponentPropsType = (property) => { property.value.type === 'Identifier' ) - if (propsTypeProperty === undefined) return null + if (propsIncludeTypeProperty === undefined) return null if ( - propsTypeProperty.type === 'Property' && - propsTypeProperty.value.type === 'Identifier' + propsIncludeTypeProperty.type === 'Property' && + propsIncludeTypeProperty.value.type === 'Identifier' ) - return propsTypeProperty.value.name + return propsIncludeTypeProperty.value.name } return null } diff --git a/tests/lib/rules/no-use-computed-property-like-method.js b/tests/lib/rules/no-use-computed-property-like-method.js index 370454498..f0d54e9a2 100644 --- a/tests/lib/rules/no-use-computed-property-like-method.js +++ b/tests/lib/rules/no-use-computed-property-like-method.js @@ -94,6 +94,48 @@ tester.run('no-use-computed-property-like-method', rule, { ` }, + { + filename: 'test.vue', + code: ` + + ` + }, { filename: 'test.vue', code: ` @@ -418,6 +460,55 @@ tester.run('no-use-computed-property-like-method', rule, { 'Use this.computedReturnDataBoolean instead of this.computedReturnDataBoolean().' ] }, + { + filename: 'test.vue', + code: ` + + `, + errors: [ + 'Use this.computedReturnPropsString instead of this.computedReturnPropsString().', + 'Use this.computedReturnPropsNumber instead of this.computedReturnPropsNumber().', + 'Use this.computedReturnPropsObject instead of this.computedReturnPropsObject().', + 'Use this.computedReturnPropsArray instead of this.computedReturnPropsArray().', + 'Use this.computedReturnPropsBoolean instead of this.computedReturnPropsBoolean().' + ] + }, { filename: 'test.vue', code: ` From 986648b4d0f95e1abc9ae8672bd886b99e7a617e Mon Sep 17 00:00:00 2001 From: tyankatsu Date: Mon, 3 May 2021 00:02:52 +0900 Subject: [PATCH 26/35] chore: run update --- docs/rules/README.md | 533 +++++++++--------- .../no-use-computed-property-like-method.md | 3 +- docs/rules/object-curly-newline.md | 4 +- 3 files changed, 271 insertions(+), 269 deletions(-) diff --git a/docs/rules/README.md b/docs/rules/README.md index 9b600d274..3d12c9fdf 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -7,9 +7,10 @@ sidebarDepth: 0 ::: tip Legend -:wrench: Indicates that the rule is fixable, and using `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the reported problems. + :wrench: Indicates that the rule is fixable, and using `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the reported problems. ::: + ## Base Rules (Enabling Correct ESLint Parsing) Enforce all the rules in this category, as well as all higher priority rules, with: @@ -20,11 +21,11 @@ Enforce all the rules in this category, as well as all higher priority rules, wi } ``` -| Rule ID | Description | | -| :------------------------------------------------------------------------ | :---------------------------------------------------------------------- | :-- | -| [vue/comment-directive](./comment-directive.md) | support comment-directives in `