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
+
+
+
Lorem ipsum
+
+
+
+
+
+```
+
+:+1: Examples of **correct** code:
+
+```json
+{
+ "vue/no-unused-components": ["error", {
+ "ignoreWhenBindingPresent": false
+ }]
+}
+```
+
+```html
+
+
+
Lorem ipsum
+
+
+
+
+
+
+
+```
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
+ }]
}
]
})