From 1222ffcd4185d17e2ad783bfc189115bb249a43d Mon Sep 17 00:00:00 2001 From: RobertAKARobin Date: Mon, 22 Jul 2024 15:52:49 -0500 Subject: [PATCH 1/9] Add disallowTabs --- .../lib/rules/no-extra-spacing-attrs.js | 44 ++++++++++++++++++- .../rules/no-extra-spacing-attrs.test.js | 43 ++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js index 1b26d344..cd91db89 100644 --- a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js +++ b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js @@ -23,6 +23,9 @@ const MESSAGE_IDS = { MISSING_BEFORE: "missingBefore", MISSING_BEFORE_SELF_CLOSE: "missingBeforeSelfClose", EXTRA_BEFORE_SELF_CLOSE: "unexpectedBeforeSelfClose", + EXTRA_TAB_BEFORE: "unexpectedTabBefore", + EXTRA_TAB_BEFORE_SELF_CLOSE: "unexpectedTabBeforeSelfClose", + EXTRA_TAB_BETWEEN: "unexpectedTabBetween", }; /** @@ -46,6 +49,9 @@ module.exports = { disallowMissing: { type: "boolean", }, + disallowTabs: { + type: "boolean", + }, enforceBeforeSelfClose: { type: "boolean", }, @@ -61,12 +67,18 @@ module.exports = { [MESSAGE_IDS.EXTRA_BEFORE_SELF_CLOSE]: "Unexpected extra spaces before self closing", [MESSAGE_IDS.MISSING_BEFORE]: "Missing space before attribute", + [MESSAGE_IDS.EXTRA_TAB_BEFORE]: "Unexpected tab before attribute; use space instead", + [MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE]: "Unexpected tab before self closing; use space instead", + [MESSAGE_IDS.EXTRA_TAB_BETWEEN]: "Unexpected tab between attributes; use space instead" }, }, create(context) { const enforceBeforeSelfClose = !!(context.options[0] || {}) .enforceBeforeSelfClose; const disallowMissing = !!(context.options[0] || {}).disallowMissing; + const disallowTabs = !!(context.options[0] || {}).disallowTabs; + + const sourceCode = context.getSourceCode().text; /** * @param {AttributeNode[]} attrs @@ -98,6 +110,16 @@ module.exports = { return fixer.insertTextAfter(current, " "); }, }); + } else if (disallowTabs) { + if (sourceCode[current.loc.end.column] === `\t`) { + context.report({ + loc: getLocBetween(current, after), + messageId: MESSAGE_IDS.EXTRA_TAB_BETWEEN, + fix(fixer) { + return fixer.replaceTextRange([current.loc.end.column, after.loc.start.column], ` `); + }, + }); + } } }); } @@ -164,6 +186,16 @@ module.exports = { ]); }, }); + } else if (disallowTabs) { + if (sourceCode[firstAttr.loc.start.column - 1] === `\t`) { + context.report({ + loc: firstAttr.loc, + messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE, + fix(fixer) { + return fixer.replaceTextRange([firstAttr.loc.start.column - 1, firstAttr.loc.start.column], ` `); + }, + }); + } } } @@ -200,6 +232,16 @@ module.exports = { return fixer.insertTextAfter(beforeSelfClosing, " "); }, }); + } else if (disallowTabs) { + if (sourceCode[openEnd.loc.start.column - 1] === `\t`) { + context.report({ + loc: openEnd.loc, + messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE, + fix(fixer) { + return fixer.replaceTextRange([openEnd.loc.start.column - 1, openEnd.loc.start.column], ` `); + }, + }); + } } } @@ -229,7 +271,7 @@ module.exports = { checkExtraSpacesBetweenAttrs(node.attributes); if ( - node.attributes.length === 0 && + node.attributes.length === 0 && // TODO: Handle when there are attributes isSelfClosing && enforceBeforeSelfClose ) { diff --git a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js index e1ca1ed4..a7a58c4c 100644 --- a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js +++ b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js @@ -383,5 +383,48 @@ ruleTester.run("no-extra-spacing-attrs", rule, { }, ], }, + { + code: ``, + output: `foo`, + options: [ + { + disallowTabs: true, + } + ], + errors: [ + { + messageId: "unexpectedTabBetween" + } + ] + }, + { + code: ``, + output: `foo`, + options: [ + { + disallowTabs: true, + } + ], + errors: [ + { + messageId: "unexpectedTabBefore" + } + ] + }, + { + code: ``, + output: ``, + options: [ + { + disallowTabs: true, + enforceBeforeSelfClose: true, + } + ], + errors: [ + { + messageId: "unexpectedTabBeforeSelfClose" + } + ] + } ], }); From fa96fce08040a761db7f038620dfad237218ca77 Mon Sep 17 00:00:00 2001 From: RobertAKARobin Date: Mon, 29 Jul 2024 14:07:50 -0500 Subject: [PATCH 2/9] Add unexpectedBeforeClose --- .../lib/rules/no-extra-spacing-attrs.js | 176 ++++++++---------- .../rules/no-extra-spacing-attrs.test.js | 40 +++- 2 files changed, 115 insertions(+), 101 deletions(-) diff --git a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js index cd91db89..301ec675 100644 --- a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js +++ b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js @@ -20,6 +20,7 @@ const MESSAGE_IDS = { EXTRA_BETWEEN: "unexpectedBetween", EXTRA_AFTER: "unexpectedAfter", EXTRA_BEFORE: "unexpectedBefore", + EXTRA_BEFORE_CLOSE: "unexpectedBeforeClose", MISSING_BEFORE: "missingBefore", MISSING_BEFORE_SELF_CLOSE: "missingBeforeSelfClose", EXTRA_BEFORE_SELF_CLOSE: "unexpectedBeforeSelfClose", @@ -62,6 +63,7 @@ module.exports = { [MESSAGE_IDS.EXTRA_BETWEEN]: "Unexpected space between attributes", [MESSAGE_IDS.EXTRA_AFTER]: "Unexpected space after attribute", [MESSAGE_IDS.EXTRA_BEFORE]: "Unexpected space before attribute", + [MESSAGE_IDS.EXTRA_BEFORE_CLOSE]: "Unexpected space before closing", [MESSAGE_IDS.MISSING_BEFORE_SELF_CLOSE]: "Missing space before self closing", [MESSAGE_IDS.EXTRA_BEFORE_SELF_CLOSE]: @@ -124,44 +126,6 @@ module.exports = { }); } - /** - * @param {OpenTagEndNode | OpenScriptTagEndNode | OpenStyleTagEndNode} openEnd - * @param {AttributeNode} lastAttr - * @param {boolean} isSelfClosed - * @returns {void} - */ - function checkExtraSpaceAfter(openEnd, lastAttr, isSelfClosed) { - if (openEnd.loc.end.line !== lastAttr.loc.end.line) { - // skip the attribute on the different line with the start tag - return; - } - const limit = isSelfClosed && enforceBeforeSelfClose ? 1 : 0; - const spacesBetween = openEnd.loc.start.column - lastAttr.loc.end.column; - - if (spacesBetween > limit) { - context.report({ - loc: getLocBetween(lastAttr, openEnd), - messageId: MESSAGE_IDS.EXTRA_AFTER, - fix(fixer) { - return fixer.removeRange([ - lastAttr.range[1], - lastAttr.range[1] + spacesBetween - limit, - ]); - }, - }); - } - - if (isSelfClosed && enforceBeforeSelfClose && spacesBetween < 1) { - context.report({ - loc: getLocBetween(lastAttr, openEnd), - messageId: MESSAGE_IDS.MISSING_BEFORE_SELF_CLOSE, - fix(fixer) { - return fixer.insertTextAfter(lastAttr, " "); - }, - }); - } - } - /** * @param {OpenScriptTagStartNode | OpenTagStartNode | OpenStyleTagStartNode} node * @param {AttributeNode} firstAttr @@ -199,52 +163,6 @@ module.exports = { } } - /** - * @param {AnyNode} beforeSelfClosing - * @param {OpenTagEndNode | OpenScriptTagEndNode | OpenStyleTagEndNode} openEnd - * @returns - */ - function checkSpaceBeforeSelfClosing(beforeSelfClosing, openEnd) { - if (beforeSelfClosing.loc.start.line !== openEnd.loc.start.line) { - // skip the attribute on the different line with the start tag - return; - } - const spacesBetween = - openEnd.loc.start.column - beforeSelfClosing.loc.end.column; - const locBetween = getLocBetween(beforeSelfClosing, openEnd); - - if (spacesBetween > 1) { - context.report({ - loc: locBetween, - messageId: MESSAGE_IDS.EXTRA_BEFORE_SELF_CLOSE, - fix(fixer) { - return fixer.removeRange([ - beforeSelfClosing.range[1] + 1, - openEnd.range[0], - ]); - }, - }); - } else if (spacesBetween < 1) { - context.report({ - loc: locBetween, - messageId: MESSAGE_IDS.MISSING_BEFORE_SELF_CLOSE, - fix(fixer) { - return fixer.insertTextAfter(beforeSelfClosing, " "); - }, - }); - } else if (disallowTabs) { - if (sourceCode[openEnd.loc.start.column - 1] === `\t`) { - context.report({ - loc: openEnd.loc, - messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE, - fix(fixer) { - return fixer.replaceTextRange([openEnd.loc.start.column - 1, openEnd.loc.start.column], ` `); - }, - }); - } - } - } - return { /** * @param {TagNode | StyleTagNode | ScriptTagNode} node @@ -259,23 +177,83 @@ module.exports = { checkExtraSpaceBefore(node.openStart, node.attributes[0]); } if (node.openEnd) { - const isSelfClosing = node.openEnd.value === "/>"; + checkExtraSpacesBetweenAttrs(node.attributes); - if (node.attributes && node.attributes.length > 0) { - checkExtraSpaceAfter( - node.openEnd, - node.attributes[node.attributes.length - 1], - isSelfClosing - ); - } + const lastAttr = node.attributes[node.attributes.length - 1]; + const nodeBeforeEnd = node.attributes.length === 0 + ? node.openStart + : lastAttr; - checkExtraSpacesBetweenAttrs(node.attributes); - if ( - node.attributes.length === 0 && // TODO: Handle when there are attributes - isSelfClosing && - enforceBeforeSelfClose - ) { - checkSpaceBeforeSelfClosing(node.openStart, node.openEnd); + if (nodeBeforeEnd.loc.end.line === node.openEnd.loc.start.line) { + const isSelfClosing = node.openEnd.value === "/>"; + + const spacesBetween = node.openEnd.loc.start.column - nodeBeforeEnd.loc.end.column; + const locBetween = getLocBetween(nodeBeforeEnd, node.openEnd); + + if (isSelfClosing && enforceBeforeSelfClose) { + if (spacesBetween < 1) { + context.report({ + loc: locBetween, + messageId: MESSAGE_IDS.MISSING_BEFORE_SELF_CLOSE, + fix(fixer) { + return fixer.insertTextAfter(nodeBeforeEnd, " "); + }, + }); + } else if (spacesBetween === 1) { + if ( + disallowTabs + && sourceCode[node.openEnd.loc.start.column - 1] === `\t` + ) { + context.report({ + loc: node.openEnd.loc, + messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE, + fix(fixer) { + return fixer.replaceTextRange( + [node.openEnd.loc.start.column - 1, node.openEnd.loc.start.column], + ` ` + ); + }, + }); + } + } else { + context.report({ + loc: locBetween, + messageId: MESSAGE_IDS.EXTRA_BEFORE_SELF_CLOSE, + fix(fixer) { + return fixer.removeRange([ + nodeBeforeEnd.range[1] + 1, + node.openEnd.range[0], + ]); + }, + }); + } + } else { + if (spacesBetween > 0) { + if (node.attributes.length > 0) { + context.report({ + loc: locBetween, + messageId: MESSAGE_IDS.EXTRA_AFTER, + fix(fixer) { + return fixer.removeRange([ + lastAttr.range[1], + node.openEnd.range[0] + ]); + }, + }); + } else { + context.report({ + loc: locBetween, + messageId: MESSAGE_IDS.EXTRA_BEFORE_CLOSE, + fix(fixer) { + return fixer.removeRange([ + node.openStart.range[1], + node.openEnd.range[0] + ]); + } + }) + } + } + } } } }, diff --git a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js index a7a58c4c..37499f96 100644 --- a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js +++ b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js @@ -309,7 +309,7 @@ ruleTester.run("no-extra-spacing-attrs", rule, { output: "", errors: [ { - messageId: "unexpectedAfter", + messageId: "unexpectedBeforeSelfClose", }, ], }, @@ -425,6 +425,42 @@ ruleTester.run("no-extra-spacing-attrs", rule, { messageId: "unexpectedTabBeforeSelfClose" } ] - } + }, + { + code: `
`, + output: `
`, + errors: [ + { + messageId: "unexpectedBeforeClose" + } + ] + }, + { + code: `
`, + output: `
`, + errors: [ + { + messageId: "unexpectedAfter" + } + ] + }, + { + code: ``, + output: `
`, + errors: [ + { + messageId: "unexpectedBeforeClose" + } + ] + }, + { + code: `
`, + output: `
`, + errors: [ + { + messageId: "unexpectedAfter" + } + ] + }, ], }); From b4b9b3f76e06315581b945da895882a8b9fdc7ea Mon Sep 17 00:00:00 2001 From: RobertAKARobin Date: Mon, 29 Jul 2024 14:14:29 -0500 Subject: [PATCH 3/9] Update docs --- docs/rules/no-extra-spacing-attrs.md | 30 +++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/rules/no-extra-spacing-attrs.md b/docs/rules/no-extra-spacing-attrs.md index d0ccead0..333fa91d 100644 --- a/docs/rules/no-extra-spacing-attrs.md +++ b/docs/rules/no-extra-spacing-attrs.md @@ -1,6 +1,6 @@ # no-extra-spacing-attrs -This rule disallows extra spaces around attributes. +This rule disallows extra spaces around attributes, and/or between the tag start and end ## How to use @@ -26,6 +26,9 @@ Examples of **incorrect** code for this rule:
+ + +
``` Examples of **correct** code for this rule: @@ -33,6 +36,7 @@ Examples of **correct** code for this rule: ```html,correct
+
``` ## Options @@ -84,3 +88,27 @@ Example(s) of **correct** code for this rule with the `{ "disallowMissing": true ``` + +- `disallowTabs` (default: false): Enforce using spaces instead of tabs between attributes + +Example(s) of **incorrect** code for this rule with the `{ "disallowTabs": true }` option: + + + +```html +
+
+``` + + + +Example(s) of **correct** code for this rule with the `{ "disallowTabs": true }` option: + + + +```html +
+
+``` + + From 32cdbfc571ffbe3def378c3ac244d03b02920ce0 Mon Sep 17 00:00:00 2001 From: RobertAKARobin Date: Mon, 29 Jul 2024 14:15:02 -0500 Subject: [PATCH 4/9] prettier --- .../lib/rules/no-extra-spacing-attrs.js | 44 ++++++++++------- .../rules/no-extra-spacing-attrs.test.js | 48 +++++++++---------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js index 301ec675..83d47ddf 100644 --- a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js +++ b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js @@ -69,9 +69,12 @@ module.exports = { [MESSAGE_IDS.EXTRA_BEFORE_SELF_CLOSE]: "Unexpected extra spaces before self closing", [MESSAGE_IDS.MISSING_BEFORE]: "Missing space before attribute", - [MESSAGE_IDS.EXTRA_TAB_BEFORE]: "Unexpected tab before attribute; use space instead", - [MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE]: "Unexpected tab before self closing; use space instead", - [MESSAGE_IDS.EXTRA_TAB_BETWEEN]: "Unexpected tab between attributes; use space instead" + [MESSAGE_IDS.EXTRA_TAB_BEFORE]: + "Unexpected tab before attribute; use space instead", + [MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE]: + "Unexpected tab before self closing; use space instead", + [MESSAGE_IDS.EXTRA_TAB_BETWEEN]: + "Unexpected tab between attributes; use space instead", }, }, create(context) { @@ -118,7 +121,10 @@ module.exports = { loc: getLocBetween(current, after), messageId: MESSAGE_IDS.EXTRA_TAB_BETWEEN, fix(fixer) { - return fixer.replaceTextRange([current.loc.end.column, after.loc.start.column], ` `); + return fixer.replaceTextRange( + [current.loc.end.column, after.loc.start.column], + ` ` + ); }, }); } @@ -156,7 +162,10 @@ module.exports = { loc: firstAttr.loc, messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE, fix(fixer) { - return fixer.replaceTextRange([firstAttr.loc.start.column - 1, firstAttr.loc.start.column], ` `); + return fixer.replaceTextRange( + [firstAttr.loc.start.column - 1, firstAttr.loc.start.column], + ` ` + ); }, }); } @@ -180,14 +189,14 @@ module.exports = { checkExtraSpacesBetweenAttrs(node.attributes); const lastAttr = node.attributes[node.attributes.length - 1]; - const nodeBeforeEnd = node.attributes.length === 0 - ? node.openStart - : lastAttr; + const nodeBeforeEnd = + node.attributes.length === 0 ? node.openStart : lastAttr; if (nodeBeforeEnd.loc.end.line === node.openEnd.loc.start.line) { const isSelfClosing = node.openEnd.value === "/>"; - const spacesBetween = node.openEnd.loc.start.column - nodeBeforeEnd.loc.end.column; + const spacesBetween = + node.openEnd.loc.start.column - nodeBeforeEnd.loc.end.column; const locBetween = getLocBetween(nodeBeforeEnd, node.openEnd); if (isSelfClosing && enforceBeforeSelfClose) { @@ -201,15 +210,18 @@ module.exports = { }); } else if (spacesBetween === 1) { if ( - disallowTabs - && sourceCode[node.openEnd.loc.start.column - 1] === `\t` + disallowTabs && + sourceCode[node.openEnd.loc.start.column - 1] === `\t` ) { context.report({ loc: node.openEnd.loc, messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE, fix(fixer) { return fixer.replaceTextRange( - [node.openEnd.loc.start.column - 1, node.openEnd.loc.start.column], + [ + node.openEnd.loc.start.column - 1, + node.openEnd.loc.start.column, + ], ` ` ); }, @@ -236,7 +248,7 @@ module.exports = { fix(fixer) { return fixer.removeRange([ lastAttr.range[1], - node.openEnd.range[0] + node.openEnd.range[0], ]); }, }); @@ -247,10 +259,10 @@ module.exports = { fix(fixer) { return fixer.removeRange([ node.openStart.range[1], - node.openEnd.range[0] + node.openEnd.range[0], ]); - } - }) + }, + }); } } } diff --git a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js index 37499f96..152d49ae 100644 --- a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js +++ b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js @@ -389,13 +389,13 @@ ruleTester.run("no-extra-spacing-attrs", rule, { options: [ { disallowTabs: true, - } + }, ], errors: [ { - messageId: "unexpectedTabBetween" - } - ] + messageId: "unexpectedTabBetween", + }, + ], }, { code: ``, @@ -403,13 +403,13 @@ ruleTester.run("no-extra-spacing-attrs", rule, { options: [ { disallowTabs: true, - } + }, ], errors: [ { - messageId: "unexpectedTabBefore" - } - ] + messageId: "unexpectedTabBefore", + }, + ], }, { code: ``, @@ -418,49 +418,49 @@ ruleTester.run("no-extra-spacing-attrs", rule, { { disallowTabs: true, enforceBeforeSelfClose: true, - } + }, ], errors: [ { - messageId: "unexpectedTabBeforeSelfClose" - } - ] + messageId: "unexpectedTabBeforeSelfClose", + }, + ], }, { code: `
`, output: `
`, errors: [ { - messageId: "unexpectedBeforeClose" - } - ] + messageId: "unexpectedBeforeClose", + }, + ], }, { code: `
`, output: `
`, errors: [ { - messageId: "unexpectedAfter" - } - ] + messageId: "unexpectedAfter", + }, + ], }, { code: ``, output: `
`, errors: [ { - messageId: "unexpectedBeforeClose" - } - ] + messageId: "unexpectedBeforeClose", + }, + ], }, { code: `
`, output: `
`, errors: [ { - messageId: "unexpectedAfter" - } - ] + messageId: "unexpectedAfter", + }, + ], }, ], }); From d67e47b5a87b9cfdb51cef97f21213e3f038945d Mon Sep 17 00:00:00 2001 From: RobertAKARobin Date: Mon, 29 Jul 2024 14:33:24 -0500 Subject: [PATCH 5/9] De-nesting some if statements --- .../lib/rules/no-extra-spacing-attrs.js | 134 +++++++++--------- 1 file changed, 69 insertions(+), 65 deletions(-) diff --git a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js index 83d47ddf..ec51b2ee 100644 --- a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js +++ b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js @@ -192,79 +192,83 @@ module.exports = { const nodeBeforeEnd = node.attributes.length === 0 ? node.openStart : lastAttr; - if (nodeBeforeEnd.loc.end.line === node.openEnd.loc.start.line) { - const isSelfClosing = node.openEnd.value === "/>"; + if (nodeBeforeEnd.loc.end.line !== node.openEnd.loc.start.line) { + return; + } - const spacesBetween = - node.openEnd.loc.start.column - nodeBeforeEnd.loc.end.column; - const locBetween = getLocBetween(nodeBeforeEnd, node.openEnd); + const isSelfClosing = node.openEnd.value === "/>"; - if (isSelfClosing && enforceBeforeSelfClose) { - if (spacesBetween < 1) { - context.report({ - loc: locBetween, - messageId: MESSAGE_IDS.MISSING_BEFORE_SELF_CLOSE, - fix(fixer) { - return fixer.insertTextAfter(nodeBeforeEnd, " "); - }, - }); - } else if (spacesBetween === 1) { - if ( - disallowTabs && - sourceCode[node.openEnd.loc.start.column - 1] === `\t` - ) { - context.report({ - loc: node.openEnd.loc, - messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE, - fix(fixer) { - return fixer.replaceTextRange( - [ - node.openEnd.loc.start.column - 1, - node.openEnd.loc.start.column, - ], - ` ` - ); - }, - }); - } - } else { + const spacesBetween = + node.openEnd.loc.start.column - nodeBeforeEnd.loc.end.column; + const locBetween = getLocBetween(nodeBeforeEnd, node.openEnd); + + if (isSelfClosing && enforceBeforeSelfClose) { + if (spacesBetween < 1) { + context.report({ + loc: locBetween, + messageId: MESSAGE_IDS.MISSING_BEFORE_SELF_CLOSE, + fix(fixer) { + return fixer.insertTextAfter(nodeBeforeEnd, " "); + }, + }); + } else if (spacesBetween === 1) { + if ( + disallowTabs && + sourceCode[node.openEnd.loc.start.column - 1] === `\t` + ) { context.report({ - loc: locBetween, - messageId: MESSAGE_IDS.EXTRA_BEFORE_SELF_CLOSE, + loc: node.openEnd.loc, + messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE, fix(fixer) { - return fixer.removeRange([ - nodeBeforeEnd.range[1] + 1, - node.openEnd.range[0], - ]); + return fixer.replaceTextRange( + [ + node.openEnd.loc.start.column - 1, + node.openEnd.loc.start.column, + ], + ` ` + ); }, }); } } else { - if (spacesBetween > 0) { - if (node.attributes.length > 0) { - context.report({ - loc: locBetween, - messageId: MESSAGE_IDS.EXTRA_AFTER, - fix(fixer) { - return fixer.removeRange([ - lastAttr.range[1], - node.openEnd.range[0], - ]); - }, - }); - } else { - context.report({ - loc: locBetween, - messageId: MESSAGE_IDS.EXTRA_BEFORE_CLOSE, - fix(fixer) { - return fixer.removeRange([ - node.openStart.range[1], - node.openEnd.range[0], - ]); - }, - }); - } - } + context.report({ + loc: locBetween, + messageId: MESSAGE_IDS.EXTRA_BEFORE_SELF_CLOSE, + fix(fixer) { + return fixer.removeRange([ + nodeBeforeEnd.range[1] + 1, + node.openEnd.range[0], + ]); + }, + }); + } + + return; + } + + if (spacesBetween > 0) { + if (node.attributes.length > 0) { + context.report({ + loc: locBetween, + messageId: MESSAGE_IDS.EXTRA_AFTER, + fix(fixer) { + return fixer.removeRange([ + lastAttr.range[1], + node.openEnd.range[0], + ]); + }, + }); + } else { + context.report({ + loc: locBetween, + messageId: MESSAGE_IDS.EXTRA_BEFORE_CLOSE, + fix(fixer) { + return fixer.removeRange([ + node.openStart.range[1], + node.openEnd.range[0], + ]); + }, + }); } } } From 8a89536a16377bdf3c45eeafecedbe6f79ad2747 Mon Sep 17 00:00:00 2001 From: RobertAKARobin Date: Mon, 29 Jul 2024 22:11:15 -0500 Subject: [PATCH 6/9] Fix tests for multiline cases --- .../lib/rules/no-extra-spacing-attrs.js | 16 ++++++++++------ .../tests/rules/no-extra-spacing-attrs.test.js | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js index ec51b2ee..f3749c7c 100644 --- a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js +++ b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js @@ -116,7 +116,7 @@ module.exports = { }, }); } else if (disallowTabs) { - if (sourceCode[current.loc.end.column] === `\t`) { + if (sourceCode[current.range[1]] === `\t`) { context.report({ loc: getLocBetween(current, after), messageId: MESSAGE_IDS.EXTRA_TAB_BETWEEN, @@ -157,13 +157,16 @@ module.exports = { }, }); } else if (disallowTabs) { - if (sourceCode[firstAttr.loc.start.column - 1] === `\t`) { + if (sourceCode[firstAttr.range[0] - 1] === `\t`) { context.report({ loc: firstAttr.loc, messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE, fix(fixer) { return fixer.replaceTextRange( - [firstAttr.loc.start.column - 1, firstAttr.loc.start.column], + [ + firstAttr.range[0] - 1, + firstAttr.range[0] + ], ` ` ); }, @@ -185,6 +188,7 @@ module.exports = { if (node.attributes.length) { checkExtraSpaceBefore(node.openStart, node.attributes[0]); } + if (node.openEnd) { checkExtraSpacesBetweenAttrs(node.attributes); @@ -214,7 +218,7 @@ module.exports = { } else if (spacesBetween === 1) { if ( disallowTabs && - sourceCode[node.openEnd.loc.start.column - 1] === `\t` + sourceCode[node.openEnd.range[0] - 1] === `\t` ) { context.report({ loc: node.openEnd.loc, @@ -222,8 +226,8 @@ module.exports = { fix(fixer) { return fixer.replaceTextRange( [ - node.openEnd.loc.start.column - 1, - node.openEnd.loc.start.column, + node.openEnd.range[0] - 1, + node.openEnd.range[0], ], ` ` ); diff --git a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js index 152d49ae..50be9c3c 100644 --- a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js +++ b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js @@ -133,6 +133,21 @@ ruleTester.run("no-extra-spacing-attrs", rule, { }, ], }, + { + code: ` +\t
+\t\t +\t\t
+\t
+`, + options: [ + { + disallowMissing: true, + disallowTabs: true, + enforceBeforeSelfClose: true + } + ] + } ], invalid: [ { From 37120a057ba016f08f539ad65d1621611d5c29a1 Mon Sep 17 00:00:00 2001 From: RobertAKARobin Date: Mon, 29 Jul 2024 22:11:42 -0500 Subject: [PATCH 7/9] Prettier --- .../eslint-plugin/lib/rules/no-extra-spacing-attrs.js | 10 ++-------- .../tests/rules/no-extra-spacing-attrs.test.js | 8 ++++---- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js index f3749c7c..03328036 100644 --- a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js +++ b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js @@ -163,10 +163,7 @@ module.exports = { messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE, fix(fixer) { return fixer.replaceTextRange( - [ - firstAttr.range[0] - 1, - firstAttr.range[0] - ], + [firstAttr.range[0] - 1, firstAttr.range[0]], ` ` ); }, @@ -225,10 +222,7 @@ module.exports = { messageId: MESSAGE_IDS.EXTRA_TAB_BEFORE_SELF_CLOSE, fix(fixer) { return fixer.replaceTextRange( - [ - node.openEnd.range[0] - 1, - node.openEnd.range[0], - ], + [node.openEnd.range[0] - 1, node.openEnd.range[0]], ` ` ); }, diff --git a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js index 50be9c3c..27e5efea 100644 --- a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js +++ b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js @@ -144,10 +144,10 @@ ruleTester.run("no-extra-spacing-attrs", rule, { { disallowMissing: true, disallowTabs: true, - enforceBeforeSelfClose: true - } - ] - } + enforceBeforeSelfClose: true, + }, + ], + }, ], invalid: [ { From feb561e4960f8dfc96db8b4718abf56ad267b6c8 Mon Sep 17 00:00:00 2001 From: RobertAKARobin Date: Mon, 29 Jul 2024 22:31:35 -0500 Subject: [PATCH 8/9] Fix using col instead of range --- packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js index 03328036..e98f89ed 100644 --- a/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js +++ b/packages/eslint-plugin/lib/rules/no-extra-spacing-attrs.js @@ -122,7 +122,7 @@ module.exports = { messageId: MESSAGE_IDS.EXTRA_TAB_BETWEEN, fix(fixer) { return fixer.replaceTextRange( - [current.loc.end.column, after.loc.start.column], + [current.range[1], current.range[1] + 1], ` ` ); }, From ea6e9830f8678c024251aea6d65c7a28db170254 Mon Sep 17 00:00:00 2001 From: RobertAKARobin Date: Mon, 29 Jul 2024 22:34:27 -0500 Subject: [PATCH 9/9] Add another multiline test case --- .../rules/no-extra-spacing-attrs.test.js | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js index 27e5efea..31ca1545 100644 --- a/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js +++ b/packages/eslint-plugin/tests/rules/no-extra-spacing-attrs.test.js @@ -477,5 +477,43 @@ ruleTester.run("no-extra-spacing-attrs", rule, { }, ], }, + { + code: ` +\t
+\t\t +\t\t
+\t +`, + output: ` +\t
+\t\t +\t\t
+\t
+`, + options: [ + { + disallowMissing: true, + disallowTabs: true, + enforceBeforeSelfClose: true, + }, + ], + errors: [ + { + messageId: "unexpectedTabBefore", + }, + { + messageId: "unexpectedTabBeforeSelfClose", + }, + { + messageId: "unexpectedTabBefore", + }, + { + messageId: "unexpectedTabBetween", + }, + { + messageId: "unexpectedAfter", + }, + ], + }, ], });