diff --git a/docs/rules/no-unused-components.md b/docs/rules/no-unused-components.md index 7220df0c6..6375c111a 100644 --- a/docs/rules/no-unused-components.md +++ b/docs/rules/no-unused-components.md @@ -64,4 +64,85 @@ Note that components registered under other than `PascalCase` name have to be ca ## :wrench: Options -Nothing. +```json +{ + "vue/no-unused-components": ["error", { + "ignoreWhenBindingPresent": true + }] +} +``` + +- `ignoreWhenBindingPresent` ... surpresses all errors if binding has been detected in the template + default `true` + + +:+1: Examples of **incorrect** code: + +```json +{ + "vue/no-unused-components": ["error", { + "ignoreWhenBindingPresent": false + }] +} +``` + +```html + + + +``` + +:+1: Examples of **correct** code: + +```json +{ + "vue/no-unused-components": ["error", { + "ignoreWhenBindingPresent": false + }] +} +``` + +```html + + + +``` diff --git a/lib/rules/no-unused-components.js b/lib/rules/no-unused-components.js index 90673dfff..aff3743b2 100644 --- a/lib/rules/no-unused-components.js +++ b/lib/rules/no-unused-components.js @@ -23,42 +23,51 @@ module.exports = { url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v5.0.0-beta.3/docs/rules/no-unused-components.md' }, fixable: null, - schema: [] + schema: [{ + type: 'object', + properties: { + ignoreWhenBindingPresent: { + type: 'boolean' + } + }, + additionalProperties: false + }] }, create (context) { + const options = context.options[0] || {} + const ignoreWhenBindingPresent = options.ignoreWhenBindingPresent !== undefined ? options.ignoreWhenBindingPresent : true const usedComponents = [] let registeredComponents = [] + let ignoreReporting = false let templateLocation return utils.defineTemplateBodyVisitor(context, { VElement (node) { - if (!utils.isCustomComponent(node)) return - let usedComponentName - - if (utils.hasAttribute(node, 'is')) { - usedComponentName = utils.findAttribute(node, 'is').value.value - } else if (utils.hasDirective(node, 'bind', 'is')) { - const directiveNode = utils.findDirective(node, 'bind', 'is') - if ( - directiveNode.value.type === 'VExpressionContainer' && - directiveNode.value.expression.type === 'Literal' - ) { - usedComponentName = directiveNode.value.expression.value - } - } else { - usedComponentName = node.rawName + if (utils.isHtmlElementNode(node) && !utils.isHtmlWellKnownElementName(node.rawName)) { + usedComponents.push(node.rawName) } + }, + "VAttribute[directive=true][key.name='bind'][key.argument='is']" (node) { + if (node.value.type !== 'VExpressionContainer') return - if (usedComponentName) { - usedComponents.push(usedComponentName) + if (node.value.expression.type === 'Literal') { + usedComponents.push(node.value.expression.value) + } else if (ignoreWhenBindingPresent) { + ignoreReporting = true } }, + "VAttribute[directive=false][key.name='is']" (node) { + usedComponents.push(node.value.value) + }, "VElement[name='template']" (rootNode) { templateLocation = templateLocation || rootNode.loc.start }, "VElement[name='template']:exit" (rootNode) { - if (rootNode.loc.start !== templateLocation) return + if ( + rootNode.loc.start !== templateLocation || + ignoreReporting + ) return registeredComponents .filter(({ name }) => { diff --git a/lib/utils/index.js b/lib/utils/index.js index b39eeba04..8c39c63d8 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -233,7 +233,7 @@ module.exports = { assert(node && node.type === 'VElement') return ( - (this.isHtmlElementNode(node) && !this.isHtmlWellKnownElementName(node.name)) || + (this.isHtmlElementNode(node) && !this.isHtmlWellKnownElementName(node.rawName)) || this.hasAttribute(node, 'is') || this.hasDirective(node, 'bind', 'is') ) @@ -280,7 +280,7 @@ module.exports = { isHtmlWellKnownElementName (name) { assert(typeof name === 'string') - return HTML_ELEMENT_NAMES.has(name.toLowerCase()) + return HTML_ELEMENT_NAMES.has(name) }, /** @@ -291,7 +291,7 @@ module.exports = { isHtmlVoidElementName (name) { assert(typeof name === 'string') - return VOID_ELEMENT_NAMES.has(name.toLowerCase()) + return VOID_ELEMENT_NAMES.has(name) }, /** diff --git a/tests/lib/rules/no-unused-components.js b/tests/lib/rules/no-unused-components.js index f412b3ecb..939413a59 100644 --- a/tests/lib/rules/no-unused-components.js +++ b/tests/lib/rules/no-unused-components.js @@ -282,6 +282,57 @@ tester.run('no-unused-components', rule, { } ` }, + { + filename: 'test.vue', + code: ` + ` + }, + + { + filename: 'test.vue', + code: ` + + `, + options: [{ ignoreWhenBindingPresent: true }] + }, // Ignore when `render` is used instead of temoplate { @@ -364,6 +415,40 @@ tester.run('no-unused-components', rule, { message: 'The "the-button" component has been registered but not used.', line: 11 }] + }, + // Setting: ignoreWhenBindingPresent + { + filename: 'test.vue', + code: ` + + `, + options: [{ ignoreWhenBindingPresent: false }], + errors: [{ + message: 'The "Foo" component has been registered but not used.', + line: 13 + }, { + message: 'The "Bar" component has been registered but not used.', + line: 14 + }] } ] })