From c4368e1a14cb5b6fcddbbdf0e3f09fca544500cd Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Thu, 29 Sep 2022 14:31:21 +0900 Subject: [PATCH] feat: [require-closing-tags] Add allowSelfClosingCustom options (fix #99) (#109) --- docs/rules/require-closing-tags.md | 44 ++++++++++++ .../lib/rules/require-closing-tags.js | 36 ++++++---- .../tests/rules/require-closing-tags.test.js | 67 +++++++++++++++++++ 3 files changed, 134 insertions(+), 13 deletions(-) diff --git a/docs/rules/require-closing-tags.md b/docs/rules/require-closing-tags.md index acf9597f..f1731b77 100644 --- a/docs/rules/require-closing-tags.md +++ b/docs/rules/require-closing-tags.md @@ -39,6 +39,10 @@ This rule has an object option for [Void Elements](https://html.spec.whatwg.org - `"selfClosing": "always"`: enforce using self closing tag on [Void Elements](https://html.spec.whatwg.org/multipage/syntax.html#void-elements). +- `"allowSelfClosingCustom": false`: (default) disallow self-closing for the custom tags. + +- `"allowSelfClosingCustom": true`: allow self-closing for the custom tags. + #### selfClosing : "never" @@ -88,6 +92,46 @@ This rule has an object option for [Void Elements](https://html.spec.whatwg.org + +#### "allowSelfClosingCustom": false + +👎 Examples of **incorrect** code for the `{ "allowSelfClosingCustom": false }` option: + + + +```html + +``` + + + +👍 Examples of **correct** code for the `{ "allowSelfClosingCustom": false }` option: + + + +```html + +``` + + + + +#### "allowSelfClosingCustom": true + + +👍 Examples of **correct** code for the `{ "allowSelfClosingCustom": true }` option: + + + +```html + + + + +``` + + + ### Further reading - [Void Elements](https://html.spec.whatwg.org/multipage/syntax.html#void-elements) diff --git a/packages/eslint-plugin/lib/rules/require-closing-tags.js b/packages/eslint-plugin/lib/rules/require-closing-tags.js index 6ede04ca..0b978661 100644 --- a/packages/eslint-plugin/lib/rules/require-closing-tags.js +++ b/packages/eslint-plugin/lib/rules/require-closing-tags.js @@ -33,6 +33,9 @@ module.exports = { selfClosing: { enum: ["always", "never"], }, + allowSelfClosingCustom: { + type: "boolean", + }, }, additionalProperties: false, }, @@ -46,12 +49,14 @@ module.exports = { }, create(context) { - let svgStacks = []; - const shouldSelfClose = context.options && context.options.length ? context.options[0].selfClosing === "always" : false; + const allowSelfClosingCustom = + context.options && context.options.length + ? context.options[0].allowSelfClosingCustom === true + : false; function checkClosingTag(node) { if (!node.close) { @@ -65,7 +70,7 @@ module.exports = { } } - function checkVoidElement(node) { + function checkVoidElement(node, shouldSelfClose, fixable) { const hasSelfClose = node.openEnd.value === "/>"; if (shouldSelfClose && !hasSelfClose) { context.report({ @@ -75,6 +80,9 @@ module.exports = { }, messageId: MESSAGE_IDS.MISSING_SELF, fix(fixer) { + if (!fixable) { + return null; + } return fixer.replaceText(node.openEnd, " />"); }, }); @@ -87,6 +95,9 @@ module.exports = { }, messageId: MESSAGE_IDS.UNEXPECTED, fix(fixer) { + if (!fixable) { + return null; + } return fixer.replaceText(node.openEnd, ">"); }, }); @@ -95,20 +106,19 @@ module.exports = { return { Tag(node) { - if (node.name === "svg") { - svgStacks.push(node); - } - if (node.selfClosing || VOID_ELEMENTS_SET.has(node.name)) { - checkVoidElement(node); + const isVoidElement = VOID_ELEMENTS_SET.has(node.name); + if ( + node.selfClosing && + allowSelfClosingCustom && + node.name.indexOf("-") !== -1 + ) { + checkVoidElement(node, true, false); + } else if (node.selfClosing || isVoidElement) { + checkVoidElement(node, shouldSelfClose, isVoidElement); } else if (node.openEnd.value !== "/>") { checkClosingTag(node); } }, - "Tag:exit"(node) { - if (node.name === "svg") { - svgStacks.push(node); - } - }, }; }, }; diff --git a/packages/eslint-plugin/tests/rules/require-closing-tags.test.js b/packages/eslint-plugin/tests/rules/require-closing-tags.test.js index b2aa994d..10c7c9d2 100644 --- a/packages/eslint-plugin/tests/rules/require-closing-tags.test.js +++ b/packages/eslint-plugin/tests/rules/require-closing-tags.test.js @@ -19,6 +19,46 @@ ruleTester.run("require-closing-tags", rule, { }, ], }, + { + code: ` `, + options: [ + { + allowSelfClosingCustom: false, + }, + ], + }, + { + code: ``, + options: [ + { + allowSelfClosingCustom: true, + }, + ], + }, + { + code: ``, + options: [ + { + allowSelfClosingCustom: true, + }, + ], + }, + { + code: ` `, + options: [ + { + allowSelfClosingCustom: true, + }, + ], + }, + { + code: ``, + options: [ + { + allowSelfClosingCustom: true, + }, + ], + }, { code: ` @@ -98,5 +138,32 @@ ruleTester.run("require-closing-tags", rule, { }, ], }, + { + code: ``, + options: [ + { + allowSelfClosingCustom: false, + }, + ], + errors: [ + { + messageId: "unexpected", + }, + ], + }, + { + code: ``, + options: [ + { + allowSelfClosingCustom: false, + }, + ], + output: null, + errors: [ + { + messageId: "unexpected", + }, + ], + }, ], });