From 41402ddd1ccb19463ef9dfa560d21549281505ff Mon Sep 17 00:00:00 2001 From: Joao Elias Arruda Date: Mon, 21 Sep 2020 17:34:09 +0200 Subject: [PATCH 1/7] Add tests --- tests/lib/rules/no-unregistered-components.js | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/lib/rules/no-unregistered-components.js b/tests/lib/rules/no-unregistered-components.js index da9e37ee2..367026909 100644 --- a/tests/lib/rules/no-unregistered-components.js +++ b/tests/lib/rules/no-unregistered-components.js @@ -393,6 +393,71 @@ tester.run('no-unregistered-components', rule, { } ` + }, + { + filename: 'test.vue', + code: ` + + + ` + }, + { + filename: 'test.vue', + code: ` + + + ` + }, + { + filename: 'test.vue', + code: ` + + + ` + }, + { + filename: 'test.vue', + code: ` + + + ` + }, + { + filename: 'test.vue', + code: ` + + + ` } ], invalid: [ From f10af623891b8abae371ea3d7f1579f48c9a8b24 Mon Sep 17 00:00:00 2001 From: Joao Elias Arruda Date: Mon, 21 Sep 2020 18:55:37 +0200 Subject: [PATCH 2/7] Modify rule to include `ignoreRecursive` argument --- lib/rules/no-unregistered-components.js | 35 ++++- tests/lib/rules/no-unregistered-components.js | 135 +++++++++++++++++- 2 files changed, 161 insertions(+), 9 deletions(-) diff --git a/lib/rules/no-unregistered-components.js b/lib/rules/no-unregistered-components.js index 56f03e40c..e5a1a7168 100644 --- a/lib/rules/no-unregistered-components.js +++ b/lib/rules/no-unregistered-components.js @@ -62,6 +62,9 @@ module.exports = { properties: { ignorePatterns: { type: 'array' + }, + ignoreRecursive: { + type: 'boolean' } }, additionalProperties: false @@ -73,14 +76,33 @@ module.exports = { const options = context.options[0] || {} /** @type {string[]} */ const ignorePatterns = options.ignorePatterns || [] + /** @type {boolean} */ + const ignoreRecursive = options.ignoreRecursive || false /** @type { { node: VElement | VDirective | VAttribute, name: string }[] } */ const usedComponentNodes = [] /** @type { { node: Property, name: string }[] } */ const registeredComponents = [] + /** @type {string} */ + let componentName = '' - return utils.defineTemplateBodyVisitor( - context, - { + return utils.compositingVisitors( + utils.defineVueVisitor(context, { + /** @param {ObjectExpression} obj */ + onVueObjectEnter(obj) { + const nameProperty = obj.properties.find( + /** + * @param {ESNode} p + * @returns {p is (Property & { key: Identifier & {name: 'name'}, value: ObjectExpression })} + */ + (p) => p.key.name === 'name' + ) + + if (nameProperty) { + componentName = nameProperty.value.value + } + } + }), + utils.defineTemplateBodyVisitor(context, { /** @param {VElement} node */ VElement(node) { if ( @@ -156,6 +178,11 @@ module.exports = { ) return false + // Check recursive components if they are ignored + if (ignoreRecursive) { + return kebabCaseName !== casing.kebabCase(componentName) + } + // Component registered as `foo-bar` cannot be used as `FooBar` if ( casing.isPascalCase(name) && @@ -178,7 +205,7 @@ module.exports = { }) ) } - }, + }), utils.executeOnVue(context, (obj) => { registeredComponents.push(...utils.getRegisteredComponents(obj)) }) diff --git a/tests/lib/rules/no-unregistered-components.js b/tests/lib/rules/no-unregistered-components.js index 367026909..ca8075991 100644 --- a/tests/lib/rules/no-unregistered-components.js +++ b/tests/lib/rules/no-unregistered-components.js @@ -405,7 +405,12 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - ` + `, + options: [ + { + ignoreRecursive: true + } + ] }, { filename: 'test.vue', @@ -418,7 +423,12 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - ` + `, + options: [ + { + ignoreRecursive: true + } + ] }, { filename: 'test.vue', @@ -431,7 +441,12 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - ` + `, + options: [ + { + ignoreRecursive: true + } + ] }, { filename: 'test.vue', @@ -444,7 +459,12 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - ` + `, + options: [ + { + ignoreRecursive: true + } + ] }, { filename: 'test.vue', @@ -457,7 +477,12 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - ` + `, + options: [ + { + ignoreRecursive: true + } + ] } ], invalid: [ @@ -648,6 +673,106 @@ tester.run('no-unregistered-components', rule, { line: 3 } ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: + 'The "CustomComponent" component has been used but not registered.', + line: 3 + } + ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: + 'The "custom-component" component has been used but not registered.', + line: 3 + } + ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: + 'The "CustomComponent" component has been used but not registered.', + line: 3 + } + ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: + 'The "CustomComponent" component has been used but not registered.', + line: 3 + } + ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: + 'The "CustomComponent" component has been used but not registered.', + line: 3 + } + ] } ] }) From d2f8ff1a959062e603930ce407687c56b21906e2 Mon Sep 17 00:00:00 2001 From: Joao Elias Arruda Date: Mon, 21 Sep 2020 19:29:34 +0200 Subject: [PATCH 3/7] Modify docs --- docs/rules/no-unregistered-components.md | 53 +++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/docs/rules/no-unregistered-components.md b/docs/rules/no-unregistered-components.md index c90b41c41..48fe35a0c 100644 --- a/docs/rules/no-unregistered-components.md +++ b/docs/rules/no-unregistered-components.md @@ -78,7 +78,8 @@ are ignored by default. ```json { "vue/no-unregistered-components": ["error", { - "ignorePatterns": [] + "ignorePatterns": [], + "ignoreRecursive": false }] } ``` @@ -131,6 +132,56 @@ are ignored by default. +- `ignoreRecursive` Suppresses all errors if component name matches its parent component name. + +``` +Beware: recursive components can cause infinite loops, so make sure you use it with a condition. +``` + +### `ignoreRecursive: true` + +Note that you have to declare explicitly the `name` property in your component to make the recursive component work. See https://vuejs.org/v2/guide/components-edge-cases.html#Recursive-Components + + + +```vue + + + + +``` + + + + + +```vue + + + + +``` + + + ## :mag: Implementation - [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-unregistered-components.js) From dfa02e2b020107ace03baf4d892cd41c76aaf3b4 Mon Sep 17 00:00:00 2001 From: Joao Elias Arruda Date: Mon, 5 Oct 2020 17:42:24 +0200 Subject: [PATCH 4/7] Address PR comments --- lib/rules/no-unregistered-components.js | 34 ++++++++++--------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/lib/rules/no-unregistered-components.js b/lib/rules/no-unregistered-components.js index e5a1a7168..060bd64bf 100644 --- a/lib/rules/no-unregistered-components.js +++ b/lib/rules/no-unregistered-components.js @@ -86,22 +86,6 @@ module.exports = { let componentName = '' return utils.compositingVisitors( - utils.defineVueVisitor(context, { - /** @param {ObjectExpression} obj */ - onVueObjectEnter(obj) { - const nameProperty = obj.properties.find( - /** - * @param {ESNode} p - * @returns {p is (Property & { key: Identifier & {name: 'name'}, value: ObjectExpression })} - */ - (p) => p.key.name === 'name' - ) - - if (nameProperty) { - componentName = nameProperty.value.value - } - } - }), utils.defineTemplateBodyVisitor(context, { /** @param {VElement} node */ VElement(node) { @@ -178,11 +162,6 @@ module.exports = { ) return false - // Check recursive components if they are ignored - if (ignoreRecursive) { - return kebabCaseName !== casing.kebabCase(componentName) - } - // Component registered as `foo-bar` cannot be used as `FooBar` if ( casing.isPascalCase(name) && @@ -206,6 +185,19 @@ module.exports = { ) } }), + utils.defineVueVisitor(context, { + /** @param {ObjectExpression} obj */ + onVueObjectEnter(obj) { + const nameProperty = utils.findProperty(obj, 'name') + + if (nameProperty && ignoreRecursive) { + registeredComponents.push({ + node: nameProperty, + name: nameProperty.value.value + }) + } + } + }), utils.executeOnVue(context, (obj) => { registeredComponents.push(...utils.getRegisteredComponents(obj)) }) From 687a151ec1101456b6f744347541d8a8ab151739 Mon Sep 17 00:00:00 2001 From: arrudaje Date: Tue, 6 Oct 2020 09:27:57 +0200 Subject: [PATCH 5/7] empty commit From 217333227830ea04a0ecfa32028e6df46c5cf62b Mon Sep 17 00:00:00 2001 From: arrudaje Date: Fri, 9 Oct 2020 12:16:35 +0200 Subject: [PATCH 6/7] Refactor no-unregistered-components to always bypass recursive components --- lib/rules/no-unregistered-components.js | 36 ++--- tests/lib/rules/no-unregistered-components.js | 135 +----------------- 2 files changed, 18 insertions(+), 153 deletions(-) diff --git a/lib/rules/no-unregistered-components.js b/lib/rules/no-unregistered-components.js index 060bd64bf..18adeff95 100644 --- a/lib/rules/no-unregistered-components.js +++ b/lib/rules/no-unregistered-components.js @@ -62,9 +62,6 @@ module.exports = { properties: { ignorePatterns: { type: 'array' - }, - ignoreRecursive: { - type: 'boolean' } }, additionalProperties: false @@ -76,17 +73,14 @@ module.exports = { const options = context.options[0] || {} /** @type {string[]} */ const ignorePatterns = options.ignorePatterns || [] - /** @type {boolean} */ - const ignoreRecursive = options.ignoreRecursive || false /** @type { { node: VElement | VDirective | VAttribute, name: string }[] } */ const usedComponentNodes = [] /** @type { { node: Property, name: string }[] } */ const registeredComponents = [] - /** @type {string} */ - let componentName = '' - return utils.compositingVisitors( - utils.defineTemplateBodyVisitor(context, { + return utils.defineTemplateBodyVisitor( + context, + { /** @param {VElement} node */ VElement(node) { if ( @@ -184,22 +178,18 @@ module.exports = { }) ) } - }), - utils.defineVueVisitor(context, { - /** @param {ObjectExpression} obj */ - onVueObjectEnter(obj) { - const nameProperty = utils.findProperty(obj, 'name') - - if (nameProperty && ignoreRecursive) { - registeredComponents.push({ - node: nameProperty, - name: nameProperty.value.value - }) - } - } - }), + }, utils.executeOnVue(context, (obj) => { registeredComponents.push(...utils.getRegisteredComponents(obj)) + + const nameProperty = utils.findProperty(obj, 'name') + + if (nameProperty) { + registeredComponents.push({ + node: nameProperty, + name: nameProperty.value.value + }) + } }) ) } diff --git a/tests/lib/rules/no-unregistered-components.js b/tests/lib/rules/no-unregistered-components.js index ca8075991..367026909 100644 --- a/tests/lib/rules/no-unregistered-components.js +++ b/tests/lib/rules/no-unregistered-components.js @@ -405,12 +405,7 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - `, - options: [ - { - ignoreRecursive: true - } - ] + ` }, { filename: 'test.vue', @@ -423,12 +418,7 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - `, - options: [ - { - ignoreRecursive: true - } - ] + ` }, { filename: 'test.vue', @@ -441,12 +431,7 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - `, - options: [ - { - ignoreRecursive: true - } - ] + ` }, { filename: 'test.vue', @@ -459,12 +444,7 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - `, - options: [ - { - ignoreRecursive: true - } - ] + ` }, { filename: 'test.vue', @@ -477,12 +457,7 @@ tester.run('no-unregistered-components', rule, { name: 'CustomComponent' } - `, - options: [ - { - ignoreRecursive: true - } - ] + ` } ], invalid: [ @@ -673,106 +648,6 @@ tester.run('no-unregistered-components', rule, { line: 3 } ] - }, - { - filename: 'test.vue', - code: ` - - - `, - errors: [ - { - message: - 'The "CustomComponent" component has been used but not registered.', - line: 3 - } - ] - }, - { - filename: 'test.vue', - code: ` - - - `, - errors: [ - { - message: - 'The "custom-component" component has been used but not registered.', - line: 3 - } - ] - }, - { - filename: 'test.vue', - code: ` - - - `, - errors: [ - { - message: - 'The "CustomComponent" component has been used but not registered.', - line: 3 - } - ] - }, - { - filename: 'test.vue', - code: ` - - - `, - errors: [ - { - message: - 'The "CustomComponent" component has been used but not registered.', - line: 3 - } - ] - }, - { - filename: 'test.vue', - code: ` - - - `, - errors: [ - { - message: - 'The "CustomComponent" component has been used but not registered.', - line: 3 - } - ] } ] }) From 121a08be50bfb30413eac2f8733718aaf17cafc9 Mon Sep 17 00:00:00 2001 From: arrudaje Date: Fri, 9 Oct 2020 12:18:17 +0200 Subject: [PATCH 7/7] Update docs --- docs/rules/no-unregistered-components.md | 53 +----------------------- 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/docs/rules/no-unregistered-components.md b/docs/rules/no-unregistered-components.md index 48fe35a0c..c90b41c41 100644 --- a/docs/rules/no-unregistered-components.md +++ b/docs/rules/no-unregistered-components.md @@ -78,8 +78,7 @@ are ignored by default. ```json { "vue/no-unregistered-components": ["error", { - "ignorePatterns": [], - "ignoreRecursive": false + "ignorePatterns": [] }] } ``` @@ -132,56 +131,6 @@ are ignored by default. -- `ignoreRecursive` Suppresses all errors if component name matches its parent component name. - -``` -Beware: recursive components can cause infinite loops, so make sure you use it with a condition. -``` - -### `ignoreRecursive: true` - -Note that you have to declare explicitly the `name` property in your component to make the recursive component work. See https://vuejs.org/v2/guide/components-edge-cases.html#Recursive-Components - - - -```vue - - - - -``` - - - - - -```vue - - - - -``` - - - ## :mag: Implementation - [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-unregistered-components.js)