From 777b1e440d5c6d45f4277c50c1eb6c622be952ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Wed, 6 Sep 2017 06:15:19 +0800 Subject: [PATCH 1/7] WIP: New: no-unused-vars (fixes #100). --- docs/rules/no-unused-vars.md | 29 ++++++++++ lib/rules/no-unused-vars.js | 89 +++++++++++++++++++++++++++++++ tests/lib/rules/no-unused-vars.js | 47 ++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 docs/rules/no-unused-vars.md create mode 100644 lib/rules/no-unused-vars.js create mode 100644 tests/lib/rules/no-unused-vars.js diff --git a/docs/rules/no-unused-vars.md b/docs/rules/no-unused-vars.md new file mode 100644 index 000000000..a48f63c33 --- /dev/null +++ b/docs/rules/no-unused-vars.md @@ -0,0 +1,29 @@ +# Disallow unused variable definitions of v-for directives or scope attributes. (no-unused-vars) + +This rule report variable definitions of v-for directives or scope attributes if those are not used. + +## :book: Rule Details + +:-1: Examples of **incorrect** code for this rule: + +```html + +``` + +:+1: Examples of **correct** code for this rule: + +```html + +``` + +## :wrench: Options + +Nothing. diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js new file mode 100644 index 000000000..824acc564 --- /dev/null +++ b/lib/rules/no-unused-vars.js @@ -0,0 +1,89 @@ +/** + * @fileoverview warn variable definitions of v-for directives or scope attributes if those are not used. + * @author 薛定谔的猫 + */ +'use strict' + +const utils = require('../utils') + +/** + * Collect used variables recursively. + * + * @param {Node} node - The node to collect. + * @param {Object} used - The object to restore result. + * @returns {Object} used variables. + */ +function collectUsed (node, used) { + if (node.type === 'VExpressionContainer') { + node.references.forEach(ref => { + used[ref.id.name] = true + }) + } + + if (node.type === 'VElement') { + node.children.forEach(child => collectUsed(child, used)) + } + + return used +} + +/** + * Creates AST event handlers for require-v-for-key. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='for']": function (node) { + const vars = node.value.expression.left + const used = collectUsed(node.parent.parent, {}) + + // report unused. + vars.filter(v => !used[v.name]).forEach(v => { + context.report({ + node, + loc: v.loc, + message: `'{{name}}' is defined but never used.`, + data: { + name: v.name + } + }) + }) + }, + + "VAttribute[directive=false][key.name='scope']": function (node) { + const used = collectUsed(node.parent.parent, {}) + + if (!used[node.value.value]) { + context.report({ + node, + loc: node.value.loc, + message: `'{{name}}' is defined but never used.`, + data: { + name: node.value.value + } + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'warn variable definitions of v-for directives or scope attributes if those are not used', + category: 'Possible Errors', + recommended: false + }, + fixable: null, + schema: [] + } +} diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js new file mode 100644 index 000000000..68884eb36 --- /dev/null +++ b/tests/lib/rules/no-unused-vars.js @@ -0,0 +1,47 @@ +/** + * @author 薛定谔的猫 + * @copyright 2017 薛定谔的猫. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/no-unused-vars') + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const tester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('no-unused-vars', rule, { + valid: [ + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + } + ], + invalid: [ + { + filename: 'test.vue', + code: '', + errors: ['\'i\' is defined but never used.'] + }, + { + filename: 'test.vue', + code: '', + errors: ['\'props\' is defined but never used.'] + } + ] +}) From ec2285e58362c68db2eda2216072afcb99c550f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sun, 17 Sep 2017 02:02:41 +0800 Subject: [PATCH 2/7] Fix: collect used didn't check attrs. & add tests. --- lib/rules/no-unused-vars.js | 5 +++++ tests/lib/rules/no-unused-vars.js | 12 +++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js index 824acc564..2b5b09b6d 100644 --- a/lib/rules/no-unused-vars.js +++ b/lib/rules/no-unused-vars.js @@ -20,8 +20,13 @@ function collectUsed (node, used) { }) } + if (node.type === 'VAttribute') { + collectUsed(node.value, used) + } + if (node.type === 'VElement') { node.children.forEach(child => collectUsed(child, used)) + node.startTag.attributes.forEach(attr => collectUsed(attr, used)) } return used diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js index 68884eb36..b7581df92 100644 --- a/tests/lib/rules/no-unused-vars.js +++ b/tests/lib/rules/no-unused-vars.js @@ -24,22 +24,24 @@ const tester = new RuleTester({ tester.run('no-unused-vars', rule, { valid: [ { - filename: 'test.vue', code: '' }, { - filename: 'test.vue', + code: '' + }, + { code: '' + }, + { + code: '' } ], invalid: [ { - filename: 'test.vue', - code: '', + code: '', errors: ['\'i\' is defined but never used.'] }, { - filename: 'test.vue', code: '', errors: ['\'props\' is defined but never used.'] } From c627564e6be5d86468292fbc3700a38830726968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sun, 17 Sep 2017 02:07:19 +0800 Subject: [PATCH 3/7] Chore: use optional param to simplify. --- lib/rules/no-unused-vars.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js index 2b5b09b6d..03dd7c2a3 100644 --- a/lib/rules/no-unused-vars.js +++ b/lib/rules/no-unused-vars.js @@ -10,10 +10,12 @@ const utils = require('../utils') * Collect used variables recursively. * * @param {Node} node - The node to collect. - * @param {Object} used - The object to restore result. + * @param {Object} used(optional) - The object to restore result. * @returns {Object} used variables. */ function collectUsed (node, used) { + used = used || {} + if (node.type === 'VExpressionContainer') { node.references.forEach(ref => { used[ref.id.name] = true @@ -42,7 +44,7 @@ function create (context) { utils.registerTemplateBodyVisitor(context, { "VAttribute[directive=true][key.name='for']": function (node) { const vars = node.value.expression.left - const used = collectUsed(node.parent.parent, {}) + const used = collectUsed(node.parent.parent) // report unused. vars.filter(v => !used[v.name]).forEach(v => { @@ -58,7 +60,7 @@ function create (context) { }, "VAttribute[directive=false][key.name='scope']": function (node) { - const used = collectUsed(node.parent.parent, {}) + const used = collectUsed(node.parent.parent) if (!used[node.value.value]) { context.report({ From 6cca458b98cf6ee08c7fd6f4f275b7a25319bbf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sun, 17 Sep 2017 06:00:01 +0800 Subject: [PATCH 4/7] use :exit. --- lib/rules/no-unused-vars.js | 90 ++++++++++++++----------------------- 1 file changed, 34 insertions(+), 56 deletions(-) diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js index 03dd7c2a3..1c603b78c 100644 --- a/lib/rules/no-unused-vars.js +++ b/lib/rules/no-unused-vars.js @@ -6,34 +6,6 @@ const utils = require('../utils') -/** - * Collect used variables recursively. - * - * @param {Node} node - The node to collect. - * @param {Object} used(optional) - The object to restore result. - * @returns {Object} used variables. - */ -function collectUsed (node, used) { - used = used || {} - - if (node.type === 'VExpressionContainer') { - node.references.forEach(ref => { - used[ref.id.name] = true - }) - } - - if (node.type === 'VAttribute') { - collectUsed(node.value, used) - } - - if (node.type === 'VElement') { - node.children.forEach(child => collectUsed(child, used)) - node.startTag.attributes.forEach(attr => collectUsed(attr, used)) - } - - return used -} - /** * Creates AST event handlers for require-v-for-key. * @@ -41,41 +13,47 @@ function collectUsed (node, used) { * @returns {Object} AST event handlers. */ function create (context) { - utils.registerTemplateBodyVisitor(context, { - "VAttribute[directive=true][key.name='for']": function (node) { - const vars = node.value.expression.left - const used = collectUsed(node.parent.parent) + const stack = [] + let unused = [] - // report unused. - vars.filter(v => !used[v.name]).forEach(v => { - context.report({ - node, - loc: v.loc, - message: `'{{name}}' is defined but never used.`, - data: { - name: v.name - } + return utils.defineTemplateBodyVisitor(context, { + 'VElement:exit' () { + unused + .forEach((node) => { + context.report({ + node, + loc: node.loc, + message: `'{{name}}' is defined but never used.`, + data: { + name: node.name + } + }) }) - }) + unused = stack.pop() }, - - "VAttribute[directive=false][key.name='scope']": function (node) { - const used = collectUsed(node.parent.parent) - - if (!used[node.value.value]) { - context.report({ - node, - loc: node.value.loc, - message: `'{{name}}' is defined but never used.`, - data: { - name: node.value.value + VElement (node) { + stack.push(unused) + unused = [] + if (node.variables) { + for (const variable of node.variables) { + unused.push(variable.id) + } + } + }, + VExpressionContainer (node) { + if (node.references) { + for (const reference of node.references) { + if (reference.mode !== 'w') { + const name = reference.id.name + unused = unused.filter((el) => el.name !== name) + stack.forEach((list, i) => { + stack[i] = list.filter((el) => el.name !== name) + }) } - }) + } } } }) - - return {} } // ------------------------------------------------------------------------------ From a3651e103f405d643581bcf3a5b1b0d85df6f2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Sun, 17 Sep 2017 06:09:45 +0800 Subject: [PATCH 5/7] add tests. --- tests/lib/rules/no-unused-vars.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js index b7581df92..36f8536d3 100644 --- a/tests/lib/rules/no-unused-vars.js +++ b/tests/lib/rules/no-unused-vars.js @@ -29,6 +29,12 @@ tester.run('no-unused-vars', rule, { { code: '' }, + { + code: '' + }, + { + code: '' + }, { code: '' }, @@ -44,6 +50,14 @@ tester.run('no-unused-vars', rule, { { code: '', errors: ['\'props\' is defined but never used.'] + }, + { + code: '', + errors: ['\'j\' is defined but never used.'] + }, + { + code: '', + errors: ['\'f\' is defined but never used.'] } ] }) From 4cfaf89457038ec2b8dcd5df700d4a192edf0e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Mon, 25 Sep 2017 01:01:08 +0800 Subject: [PATCH 6/7] =?UTF-8?q?simplify=20,,=D4=BE=E3=85=82=D4=BE,,?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/rules/no-unused-vars.js | 39 ++++++------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js index 1c603b78c..c329aecf8 100644 --- a/lib/rules/no-unused-vars.js +++ b/lib/rules/no-unused-vars.js @@ -13,43 +13,16 @@ const utils = require('../utils') * @returns {Object} AST event handlers. */ function create (context) { - const stack = [] - let unused = [] - return utils.defineTemplateBodyVisitor(context, { - 'VElement:exit' () { - unused - .forEach((node) => { + VElement (node) { + for (const variable of node.variables) { + if (variable.references.length === 0) { context.report({ - node, - loc: node.loc, + node: variable.id, + loc: variable.id.loc, message: `'{{name}}' is defined but never used.`, - data: { - name: node.name - } + data: variable.id }) - }) - unused = stack.pop() - }, - VElement (node) { - stack.push(unused) - unused = [] - if (node.variables) { - for (const variable of node.variables) { - unused.push(variable.id) - } - } - }, - VExpressionContainer (node) { - if (node.references) { - for (const reference of node.references) { - if (reference.mode !== 'w') { - const name = reference.id.name - unused = unused.filter((el) => el.name !== name) - stack.forEach((list, i) => { - stack[i] = list.filter((el) => el.name !== name) - }) - } } } } From 7567208a8ae68e8d40c9fbac46de973554f278be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=9B=E5=AE=9A=E8=B0=94=E7=9A=84=E7=8C=AB?= Date: Mon, 25 Sep 2017 02:08:49 +0800 Subject: [PATCH 7/7] add tests. --- tests/lib/rules/no-unused-vars.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js index 36f8536d3..92812ebcb 100644 --- a/tests/lib/rules/no-unused-vars.js +++ b/tests/lib/rules/no-unused-vars.js @@ -58,6 +58,10 @@ tester.run('no-unused-vars', rule, { { code: '', errors: ['\'f\' is defined but never used.'] + }, + { + code: '', + errors: ['\'v\' is defined but never used.', '\'i\' is defined but never used.', '\'c\' is defined but never used.'] } ] })