diff --git a/docs/rules/enforce-consistent-line-wrapping.md b/docs/rules/enforce-consistent-line-wrapping.md index 9939c34..98f1565 100644 --- a/docs/rules/enforce-consistent-line-wrapping.md +++ b/docs/rules/enforce-consistent-line-wrapping.md @@ -9,6 +9,7 @@ Enforce tailwind classes to be broken up into multiple lines. It is possible to ### `printWidth` The maximum line length. Lines are wrapped appropriately to stay within this limit. The value `0` disables line wrapping by `printWidth`. + Tabs count according to [`tabWidth`](#tabwidth) when evaluating this limit. **Type**: `number` **Default**: `80` @@ -51,6 +52,16 @@ Enforce tailwind classes to be broken up into multiple lines. It is possible to
+### `tabWidth` + + Determines how many columns a tab character contributes when checking `printWidth`. + This option only affects width calculations and does not change emitted indentation characters. + + **Type**: `number` + **Default**: `1` + +
+ ### `lineBreakStyle` The line break style. diff --git a/src/rules/enforce-consistent-line-wrapping.test.ts b/src/rules/enforce-consistent-line-wrapping.test.ts index 4da092a..ef10e2f 100644 --- a/src/rules/enforce-consistent-line-wrapping.test.ts +++ b/src/rules/enforce-consistent-line-wrapping.test.ts @@ -841,6 +841,90 @@ describe(enforceConsistentLineWrapping.name, () => { ); }); + it("should use tabWidth when checking printWidth", () => { + + const dirty = "a b c d"; + const clean = "\n\ta b c\n\td\n"; + + lint( + enforceConsistentLineWrapping, + { + invalid: [ + { + jsx: `() => `, + jsxOutput: `() => `, + svelte: ``, + svelteOutput: ``, + + errors: 1, + options: [{ classesPerLine: 0, indent: "tab", printWidth: 10, tabWidth: 4 }] + } + ] + } + ); + }); + + it("should default tabWidth to 1 when it is not configured", () => { + lint( + enforceConsistentLineWrapping, + { + invalid: [ + { + jsx: `() => `, + jsxOutput: `() => `, + svelte: ``, + svelteOutput: ``, + + errors: 1, + options: [{ classesPerLine: 0, indent: "tab", printWidth: 10 }] + } + ] + } + ); + }); + + it("should not apply tabWidth when indentation uses spaces", () => { + lint( + enforceConsistentLineWrapping, + { + invalid: [ + { + jsx: `() => `, + jsxOutput: `() => `, + svelte: ``, + svelteOutput: ``, + + errors: 1, + options: [{ classesPerLine: 0, indent: 2, printWidth: 10, tabWidth: 8 }] + } + ] + } + ); + }); + + it("should still ignore printWidth when it is set to 0 even with tabWidth", () => { + + const dirty = "a b c d"; + const clean = "\n\ta b c\n\td\n"; + + lint( + enforceConsistentLineWrapping, + { + invalid: [ + { + jsx: `() => `, + jsxOutput: `() => `, + svelte: ``, + svelteOutput: ``, + + errors: 1, + options: [{ classesPerLine: 3, indent: "tab", printWidth: 0, tabWidth: 4 }] + } + ] + } + ); + }); + it("should warn if `lineBreakStyle` is likely misconfigured", async () => { { @@ -975,7 +1059,6 @@ describe(enforceConsistentLineWrapping.name, () => { // #52 it("should wrap expressions even if `group` is set to `never`", () => { - const expression = "${true ? 'b' : 'c'}"; const correct = dedent` @@ -997,7 +1080,6 @@ describe(enforceConsistentLineWrapping.name, () => { ] } ); - }); it("should be possible to change group separation by emptyLines", () => { @@ -1099,7 +1181,34 @@ describe(enforceConsistentLineWrapping.name, () => { ] } ); + }); + + it("should still start on a new line when `group` is set to `never` except if `preferSingleLine` is enabled", () => { + lint( + enforceConsistentLineWrapping, + { + valid: [ + { + angular: ``, + html: ``, + jsx: `() => `, + svelte: ``, + vue: ``, + + options: [{ group: "never", preferSingleLine: false, printWidth: 100 }] + }, + { + angular: ``, + html: ``, + jsx: `() => `, + svelte: ``, + vue: ``, + options: [{ group: "never", preferSingleLine: true, printWidth: 100 }] + } + ] + } + ); }); it("should remove duplicate classes in string literals in defined tagged template literals", () => { diff --git a/src/rules/enforce-consistent-line-wrapping.ts b/src/rules/enforce-consistent-line-wrapping.ts index 01eecf5..da67e05 100644 --- a/src/rules/enforce-consistent-line-wrapping.ts +++ b/src/rules/enforce-consistent-line-wrapping.ts @@ -103,6 +103,14 @@ export const enforceConsistentLineWrapping = createRule({ description("Enable this option if prettier is used in your project.") ), "strict" + ), + tabWidth: optional( + pipe( + number(), + minValue(1), + description("The visual width of a tab character when evaluating printWidth.") + ), + 1 ) }), @@ -239,8 +247,7 @@ function lintLiterals(ctx: Context, litera const simulatedLine = multilineClasses.line .clone() - .addClass(className) - .toString(); + .addClass(className); // wrap after the first sticky class if( @@ -582,7 +589,22 @@ class Line { } public get length() { - return this.toString().length; + const line = this.toString(); + const { tabWidth } = this.ctx.options; + + if(tabWidth <= 1 || !line.includes("\t")){ + return line.length; + } + + let width = 0; + + for(let i = 0; i < line.length; i++){ + width += line[i] === "\t" + ? tabWidth + : 1; + } + + return width; } public get classCount() {