From 0fb170b1f26fe2921a2ed3cfd96d541bd0660c15 Mon Sep 17 00:00:00 2001 From: Yak Jun Xiang Date: Tue, 21 Mar 2017 00:21:53 +0800 Subject: [PATCH] autofix for max-props-per-line --- README.md | 2 +- docs/rules/jsx-max-props-per-line.md | 2 + lib/rules/jsx-max-props-per-line.js | 28 +++++- tests/lib/rules/jsx-max-props-per-line.js | 106 +++++++++++++++++++--- 4 files changed, 122 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 1f1441a5a5..bd7b856be9 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](# * [react/jsx-indent](docs/rules/jsx-indent.md): Validate JSX indentation (fixable) * [react/jsx-indent-props](docs/rules/jsx-indent-props.md): Validate props indentation in JSX (fixable) * [react/jsx-key](docs/rules/jsx-key.md): Validate JSX has key prop when in array or iterator -* [react/jsx-max-props-per-line](docs/rules/jsx-max-props-per-line.md): Limit maximum of props on a single line in JSX +* [react/jsx-max-props-per-line](docs/rules/jsx-max-props-per-line.md): Limit maximum of props on a single line in JSX (fixable) * [react/jsx-no-bind](docs/rules/jsx-no-bind.md): Prevent usage of `.bind()` and arrow functions in JSX props * [react/jsx-no-comment-textnodes](docs/rules/jsx-no-comment-textnodes.md): Prevent comments from being inserted as text nodes * [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md): Prevent duplicate props in JSX diff --git a/docs/rules/jsx-max-props-per-line.md b/docs/rules/jsx-max-props-per-line.md index 6857162503..d0a167c857 100644 --- a/docs/rules/jsx-max-props-per-line.md +++ b/docs/rules/jsx-max-props-per-line.md @@ -2,6 +2,8 @@ Limiting the maximum of props on a single line can improve readability. +**Fixable:** This rule is automatically fixable using the `--fix` flag on the command line. However, fix does not include indentation. Please rerun lint to correct those errors. + ## Rule Details This rule checks all JSX elements and verifies that the number of props per line do not exceed the maximum allowed. Props are considered to be in a new line if there is a line break between the start of the prop and the end of the previous prop. A spread attribute counts as one prop. This rule is off by default and when on the default maximum of props on one line is `1`. diff --git a/lib/rules/jsx-max-props-per-line.js b/lib/rules/jsx-max-props-per-line.js index c4344fd8f2..88bd8370e3 100644 --- a/lib/rules/jsx-max-props-per-line.js +++ b/lib/rules/jsx-max-props-per-line.js @@ -16,7 +16,7 @@ module.exports = { category: 'Stylistic Issues', recommended: false }, - + fixable: 'code', schema: [{ type: 'object', properties: { @@ -46,6 +46,25 @@ module.exports = { return propNode.name.name; } + function generateFixFunction(line, max) { + var output = []; + var front = line[0].start; + var back = line[line.length - 1].end; + for (var i = 0; i < line.length; i += max) { + var nodes = line.slice(i, i + max); + output.push(nodes.reduce(function(prev, curr) { + if (prev === '') { + return sourceCode.getText(curr); + } + return `${prev} ${sourceCode.getText(curr)}`; + }, '')); + } + var code = output.join('\n'); + return function(fixer) { + return fixer.replaceTextRange([front, back], code); + }; + } + return { JSXOpeningElement: function (node) { if (!node.attributes.length) { @@ -59,7 +78,7 @@ module.exports = { var firstProp = node.attributes[0]; var linePartitionedProps = [[firstProp]]; - node.attributes.reduce(function(last, decl) { + node.attributes.reduce(function (last, decl) { if (last.loc.end.line === decl.loc.start.line) { linePartitionedProps[linePartitionedProps.length - 1].push(decl); } else { @@ -68,12 +87,13 @@ module.exports = { return decl; }); - linePartitionedProps.forEach(function(propsInLine) { + linePartitionedProps.forEach(function (propsInLine) { if (propsInLine.length > maximum) { var name = getPropName(propsInLine[maximum]); context.report({ node: propsInLine[maximum], - message: `Prop \`${name}\` must be placed on a new line` + message: `Prop \`${name}\` must be placed on a new line`, + fix: generateFixFunction(propsInLine, maximum) }); } }); diff --git a/tests/lib/rules/jsx-max-props-per-line.js b/tests/lib/rules/jsx-max-props-per-line.js index 00ea0d42aa..1966e5e657 100644 --- a/tests/lib/rules/jsx-max-props-per-line.js +++ b/tests/lib/rules/jsx-max-props-per-line.js @@ -64,17 +64,37 @@ ruleTester.run('jsx-max-props-per-line', rule, { invalid: [{ code: ';', - errors: [{message: 'Prop `bar` must be placed on a new line'}] + output: [ + ';' + ].join('\n'), + errors: [{message: 'Prop `bar` must be placed on a new line'}], + parserOptions: parserOptions }, { code: ';', + output: [ + ';' + ].join('\n'), options: [{maximum: 2}], errors: [{message: 'Prop `baz` must be placed on a new line'}] }, { code: ';', - errors: [{message: 'Prop `bar` must be placed on a new line'}] + output: [ + ';' + ].join('\n'), + errors: [{message: 'Prop `bar` must be placed on a new line'}], + parserOptions: parserOptions }, { code: ';', - errors: [{message: 'Prop `this.props` must be placed on a new line'}] + output: [ + ';' + ].join('\n'), + errors: [{message: 'Prop `this.props` must be placed on a new line'}], + parserOptions: parserOptions }, { code: [ '' ].join('\n'), - errors: [{message: 'Prop `bar` must be placed on a new line'}] + output: [ + '' + ].join('\n'), + errors: [{message: 'Prop `bar` must be placed on a new line'}], + parserOptions: parserOptions }, { code: [ '' ].join('\n'), - errors: [{message: 'Prop `this.props` must be placed on a new line'}] + output: [ + '' + ].join('\n'), + errors: [{message: 'Prop `this.props` must be placed on a new line'}], + parserOptions: parserOptions }, { code: [ '' ].join('\n'), - errors: [{message: 'Prop `bar` must be placed on a new line'}] + output: [ + '' + ].join('\n'), + errors: [{message: 'Prop `bar` must be placed on a new line'}], + parserOptions: parserOptions }, { code: [ '' ].join('\n'), - errors: [{message: 'Prop `bar` must be placed on a new line'}] + output: [ + '' + ].join('\n'), + errors: [{message: 'Prop `bar` must be placed on a new line'}], + parserOptions: parserOptions }, { code: [ '' ].join('\n'), + output: [ + '' + ].join('\n'), options: [{maximum: 2}], errors: [{message: 'Prop `baz` must be placed on a new line'}] }, { @@ -117,14 +172,27 @@ ruleTester.run('jsx-max-props-per-line', rule, { '' ].join('\n'), - errors: [{message: 'Prop `rest` must be placed on a new line'}] + output: [ + '' + ].join('\n'), + errors: [{message: 'Prop `rest` must be placed on a new line'}], + parserOptions: parserOptions }, { code: [ '' ].join('\n'), - errors: [{message: 'Prop `bar` must be placed on a new line'}] + output: [ + '' + ].join('\n'), + errors: [{message: 'Prop `bar` must be placed on a new line'}], + parserOptions: parserOptions }, { code: [ '' ].join('\n'), - errors: [{message: 'Prop `rest` must be placed on a new line'}] + output: [ + '' + ].join('\n'), + errors: [{message: 'Prop `rest` must be placed on a new line'}], + parserOptions: parserOptions }, { code: [ '' + ].join('\n'), + output: [ + '' ].join('\n'), options: [{maximum: 2}],