From a0852ea32302f2a91cfbb6ae76c2723b165a0b7a Mon Sep 17 00:00:00 2001 From: sil0rak Date: Sat, 18 Sep 2021 18:11:52 +0300 Subject: [PATCH 1/5] feat: allow complex config --- lib/rules/jsx-max-props-per-line.js | 64 ++++++++++++++++++++--- tests/lib/rules/jsx-max-props-per-line.js | 19 ++++++- 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/lib/rules/jsx-max-props-per-line.js b/lib/rules/jsx-max-props-per-line.js index 208891e070..c8170ed585 100644 --- a/lib/rules/jsx-max-props-per-line.js +++ b/lib/rules/jsx-max-props-per-line.js @@ -29,8 +29,22 @@ module.exports = { type: 'object', properties: { maximum: { - type: 'integer', - minimum: 1 + oneOf: [{ + type: 'integer', + minimum: 1 + }, { + type: 'object', + properties: { + single: { + type: 'integer', + minimun: 1, + }, + multi: { + type: 'integer', + minimun: 1, + } + } + }] }, when: { type: 'string', @@ -42,8 +56,30 @@ module.exports = { create(context) { const configuration = context.options[0] || {}; - const maximum = configuration.maximum || 1; - const when = configuration.when || 'always'; + let maximum = configuration.maximum || {}; + + let maximumSingle = null; + let maximumMulti = null; + + const isExtendedConfig = typeof maximum !== 'number'; + + if (isExtendedConfig) { + maximum = configuration.maximum || {}; + maximumSingle = configuration.maximum.single || 1; + maximumMulti = configuration.maximum.multiple || 1; + } + + function reportError(propInLine, fix) { + context.report({ + node: propInLine, + message: `Prop \`${getPropName(propInLine)}\` must be placed on a new line`, + fix + }); + } + + const when = isExtendedConfig + ? 'always' + : configuration.when || 'always'; function getPropName(propNode) { if (propNode.type === 'JSXSpreadAttribute') { @@ -57,6 +93,7 @@ module.exports = { const output = []; const front = line[0].range[0]; const back = line[line.length - 1].range[1]; + for (let i = 0; i < line.length; i += max) { const nodes = line.slice(i, i + max); output.push(nodes.reduce((prev, curr) => { @@ -66,7 +103,9 @@ module.exports = { return `${prev} ${sourceCode.getText(curr)}`; }, '')); } + const code = output.join('\n'); + return function fix(fixer) { return fixer.replaceTextRange([front, back], code); }; @@ -84,6 +123,15 @@ module.exports = { const firstProp = node.attributes[0]; const linePartitionedProps = [[firstProp]]; + const isSingleLineTag = linePartitionedProps.length <= 1; + + let maxPropsCountPerLine = maximum; + + if (isExtendedConfig) { + maxPropsCountPerLine = isSingleLineTag + ? maximumSingle + : maximumMulti; + } node.attributes.reduce((last, decl) => { if (last.loc.end.line === decl.loc.start.line) { @@ -95,15 +143,15 @@ module.exports = { }); linePartitionedProps.forEach((propsInLine) => { - if (propsInLine.length > maximum) { - const name = getPropName(propsInLine[maximum]); + if (propsInLine.length > maxPropsCountPerLine) { + const name = getPropName(propsInLine[maxPropsCountPerLine]); context.report({ - node: propsInLine[maximum], + node: propsInLine[maxPropsCountPerLine], messageId: 'newLine', data: { prop: name }, - fix: generateFixFunction(propsInLine, maximum) + fix: generateFixFunction(propsInLine, maxPropsCountPerLine) }); } }); diff --git a/tests/lib/rules/jsx-max-props-per-line.js b/tests/lib/rules/jsx-max-props-per-line.js index 86e8d9203c..6155be746c 100644 --- a/tests/lib/rules/jsx-max-props-per-line.js +++ b/tests/lib/rules/jsx-max-props-per-line.js @@ -60,7 +60,24 @@ ruleTester.run('jsx-max-props-per-line', rule, { '/>' ].join('\n'), options: [{maximum: 2}] - }], + }, { + code: [ + '' + ].join('\n'), + options: [{maximum: { multi: 2 }}] + }, { + code: [ + '' + ].join('\n'), + options: [{maximum: { multi: 2, single: 1 }}] + } + ], invalid: [{ code: ';', From 1205d464855a70c7132d91799e8ee9e7feb6199f Mon Sep 17 00:00:00 2001 From: Carlux Date: Sat, 18 Sep 2021 21:29:35 +0300 Subject: [PATCH 2/5] fix: logic --- lib/rules/jsx-max-props-per-line.js | 47 +++++------- tests/lib/rules/jsx-max-props-per-line.js | 89 ++++++++++++++++++++++- 2 files changed, 105 insertions(+), 31 deletions(-) diff --git a/lib/rules/jsx-max-props-per-line.js b/lib/rules/jsx-max-props-per-line.js index c8170ed585..cdbcce4fae 100644 --- a/lib/rules/jsx-max-props-per-line.js +++ b/lib/rules/jsx-max-props-per-line.js @@ -29,7 +29,7 @@ module.exports = { type: 'object', properties: { maximum: { - oneOf: [{ + oneOf: [{ type: 'integer', minimum: 1 }, { @@ -37,11 +37,11 @@ module.exports = { properties: { single: { type: 'integer', - minimun: 1, + minimum: 1 }, multi: { type: 'integer', - minimun: 1, + minimum: 1 } } }] @@ -56,27 +56,17 @@ module.exports = { create(context) { const configuration = context.options[0] || {}; - let maximum = configuration.maximum || {}; - + const maximum = configuration.maximum || 1; let maximumSingle = null; let maximumMulti = null; const isExtendedConfig = typeof maximum !== 'number'; - + if (isExtendedConfig) { - maximum = configuration.maximum || {}; - maximumSingle = configuration.maximum.single || 1; - maximumMulti = configuration.maximum.multiple || 1; + maximumSingle = maximum.single || 1; + maximumMulti = maximum.multi || 1; } - function reportError(propInLine, fix) { - context.report({ - node: propInLine, - message: `Prop \`${getPropName(propInLine)}\` must be placed on a new line`, - fix - }); - } - const when = isExtendedConfig ? 'always' : configuration.when || 'always'; @@ -105,7 +95,7 @@ module.exports = { } const code = output.join('\n'); - + return function fix(fixer) { return fixer.replaceTextRange([front, back], code); }; @@ -117,21 +107,14 @@ module.exports = { return; } - if (when === 'multiline' && node.loc.start.line === node.loc.end.line) { + const isSingleLineTag = node.loc.start.line === node.loc.end.line; + + if (when === 'multiline' && isSingleLineTag) { return; } const firstProp = node.attributes[0]; const linePartitionedProps = [[firstProp]]; - const isSingleLineTag = linePartitionedProps.length <= 1; - - let maxPropsCountPerLine = maximum; - - if (isExtendedConfig) { - maxPropsCountPerLine = isSingleLineTag - ? maximumSingle - : maximumMulti; - } node.attributes.reduce((last, decl) => { if (last.loc.end.line === decl.loc.start.line) { @@ -142,7 +125,15 @@ module.exports = { return decl; }); + let maxPropsCountPerLine = maximum; + linePartitionedProps.forEach((propsInLine) => { + if (isExtendedConfig) { + maxPropsCountPerLine = propsInLine[0].loc.start.line === node.loc.start.line + ? maximumSingle + : maximumMulti; + } + if (propsInLine.length > maxPropsCountPerLine) { const name = getPropName(propsInLine[maxPropsCountPerLine]); context.report({ diff --git a/tests/lib/rules/jsx-max-props-per-line.js b/tests/lib/rules/jsx-max-props-per-line.js index 6155be746c..0f9456fa3c 100644 --- a/tests/lib/rules/jsx-max-props-per-line.js +++ b/tests/lib/rules/jsx-max-props-per-line.js @@ -67,15 +67,15 @@ ruleTester.run('jsx-max-props-per-line', rule, { ' baz', '/>' ].join('\n'), - options: [{maximum: { multi: 2 }}] + options: [{maximum: {multi: 2}}] }, { code: [ - '' ].join('\n'), - options: [{maximum: { multi: 2, single: 1 }}] + options: [{maximum: {multi: 2, single: 1}}] } ], @@ -283,5 +283,88 @@ ruleTester.run('jsx-max-props-per-line', rule, { messageId: 'newLine', data: {prop: 'baz'} }] + }, + // new + { + code: '', + output: [ + '' + ].join('\n'), + options: [{maximum: {single: 1, multi: 1}}], + errors: [{ + messageId: 'newLine', + data: {prop: 'bar'} + }] + }, { + code: [ + '' + ].join('\n'), + output: [ + '' + ].join('\n'), + options: [{maximum: {single: 1, multi: 1}}], + errors: [{ + messageId: 'newLine', + data: {prop: 'bar'} + }] + }, { + code: [ + '' + ].join('\n'), + output: [ + '' + ].join('\n'), + options: [{maximum: {single: 1, multi: 1}}], + errors: [{ + messageId: 'newLine', + data: {prop: 'baz'} + }] + }, { + code: [ + '' + ].join('\n'), + output: [ + '' + ].join('\n'), + options: [{maximum: {single: 1, multi: 2}}], + errors: [ + { + messageId: 'newLine', + data: {prop: 'bar'} + }, { + messageId: 'newLine', + data: {prop: 'bor'} + }] + }, { + code: '', + output: [ + '' + ].join('\n'), + options: [{maximum: {single: 3, multi: 2}}], + errors: [ + { + messageId: 'newLine', + data: {prop: 'bor'} + }] }] }); From 5ae2ae45d92a848e3f20e6e7b3e3753f7c485753 Mon Sep 17 00:00:00 2001 From: Carlux Date: Sat, 18 Sep 2021 22:16:29 +0300 Subject: [PATCH 3/5] chore: update documentation --- docs/rules/jsx-max-props-per-line.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/rules/jsx-max-props-per-line.md b/docs/rules/jsx-max-props-per-line.md index d40180c716..a182a70b21 100644 --- a/docs/rules/jsx-max-props-per-line.md +++ b/docs/rules/jsx-max-props-per-line.md @@ -39,6 +39,10 @@ Examples of **correct** code for this rule: ... "react/jsx-max-props-per-line": [, { "maximum": , "when": }] ... + +... +"react/jsx-max-props-per-line": [, { "maximum": { single multi: } }] +... ``` ### `maximum` @@ -62,8 +66,12 @@ Examples of **correct** code for this rule: />; ``` +Maximum can be specified as object `{ single: 1, multi: 1 }` to specify maximum allowed number of props for single line and multiple line tags. + ### `when` + _when only applied if `maximum` is specified as number._ + Possible values: - `always` (default) - Always check for max props per line. - `multiline` - Only check for max props per line when jsx tag spans multiple lines. From 394fa00c5cc907cca682c483f9a68af7804757e5 Mon Sep 17 00:00:00 2001 From: Carlux Date: Sat, 18 Sep 2021 22:18:57 +0300 Subject: [PATCH 4/5] chore: remove comment --- docs/rules/jsx-max-props-per-line.md | 2 ++ tests/lib/rules/jsx-max-props-per-line.js | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/rules/jsx-max-props-per-line.md b/docs/rules/jsx-max-props-per-line.md index a182a70b21..5bae2076cf 100644 --- a/docs/rules/jsx-max-props-per-line.md +++ b/docs/rules/jsx-max-props-per-line.md @@ -40,6 +40,8 @@ Examples of **correct** code for this rule: "react/jsx-max-props-per-line": [, { "maximum": , "when": }] ... +// OR + ... "react/jsx-max-props-per-line": [, { "maximum": { single multi: } }] ... diff --git a/tests/lib/rules/jsx-max-props-per-line.js b/tests/lib/rules/jsx-max-props-per-line.js index 0f9456fa3c..ffd130fdbb 100644 --- a/tests/lib/rules/jsx-max-props-per-line.js +++ b/tests/lib/rules/jsx-max-props-per-line.js @@ -284,7 +284,6 @@ ruleTester.run('jsx-max-props-per-line', rule, { data: {prop: 'baz'} }] }, - // new { code: '', output: [ From d05a2cfaaa4eb2293a416ac1993e4eee13226894 Mon Sep 17 00:00:00 2001 From: Carlux Date: Sun, 19 Sep 2021 17:18:52 +0300 Subject: [PATCH 5/5] chore: add more test cases --- tests/lib/rules/jsx-max-props-per-line.js | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/lib/rules/jsx-max-props-per-line.js b/tests/lib/rules/jsx-max-props-per-line.js index ffd130fdbb..7002988721 100644 --- a/tests/lib/rules/jsx-max-props-per-line.js +++ b/tests/lib/rules/jsx-max-props-per-line.js @@ -76,6 +76,20 @@ ruleTester.run('jsx-max-props-per-line', rule, { '/>' ].join('\n'), options: [{maximum: {multi: 2, single: 1}}] + }, { + code: '', + options: [{maximum: {multi: 2, single: 3}}] + }, { + code: '', + options: [{maximum: {single: 2}}] + }, { + code: [ + '' + ].join('\n'), + options: [{maximum: {multi: 2, single: 1}}] } ], @@ -365,5 +379,47 @@ ruleTester.run('jsx-max-props-per-line', rule, { messageId: 'newLine', data: {prop: 'bor'} }] + }, { + code: [ + '' + ].join('\n'), + output: [ + '' + ].join('\n'), + options: [{maximum: {multi: 2}}], + errors: [{ + messageId: 'newLine', + data: {prop: 'baz'} + }] + }, { + code: [ + '' + ].join('\n'), + output: [ + '' + ].join('\n'), + options: [{maximum: {multi: 2, single: 1}}], + errors: [{ + messageId: 'newLine', + data: {prop: 'fuz'} + }, { + messageId: 'newLine', + data: {prop: 'baz'} + }] }] });