From 945c6106ad1b6454e2e957050cec77986b3607bf Mon Sep 17 00:00:00 2001 From: Carlux Date: Sun, 19 Sep 2021 18:20:49 +0300 Subject: [PATCH] [feat] allow both single and multi line config --- docs/rules/jsx-max-props-per-line.md | 10 ++ lib/rules/jsx-max-props-per-line.js | 55 ++++++-- tests/lib/rules/jsx-max-props-per-line.js | 157 +++++++++++++++++++++- 3 files changed, 213 insertions(+), 9 deletions(-) diff --git a/docs/rules/jsx-max-props-per-line.md b/docs/rules/jsx-max-props-per-line.md index d40180c716..5bae2076cf 100644 --- a/docs/rules/jsx-max-props-per-line.md +++ b/docs/rules/jsx-max-props-per-line.md @@ -39,6 +39,12 @@ 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: } }] +... ``` ### `maximum` @@ -62,8 +68,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. diff --git a/lib/rules/jsx-max-props-per-line.js b/lib/rules/jsx-max-props-per-line.js index 208891e070..cdbcce4fae 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', + minimum: 1 + }, + multi: { + type: 'integer', + minimum: 1 + } + } + }] }, when: { type: 'string', @@ -43,7 +57,19 @@ module.exports = { create(context) { const configuration = context.options[0] || {}; const maximum = configuration.maximum || 1; - const when = configuration.when || 'always'; + let maximumSingle = null; + let maximumMulti = null; + + const isExtendedConfig = typeof maximum !== 'number'; + + if (isExtendedConfig) { + maximumSingle = maximum.single || 1; + maximumMulti = maximum.multi || 1; + } + + const when = isExtendedConfig + ? 'always' + : configuration.when || 'always'; function getPropName(propNode) { if (propNode.type === 'JSXSpreadAttribute') { @@ -57,6 +83,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 +93,9 @@ module.exports = { return `${prev} ${sourceCode.getText(curr)}`; }, '')); } + const code = output.join('\n'); + return function fix(fixer) { return fixer.replaceTextRange([front, back], code); }; @@ -78,7 +107,9 @@ 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; } @@ -94,16 +125,24 @@ module.exports = { return decl; }); + let maxPropsCountPerLine = maximum; + linePartitionedProps.forEach((propsInLine) => { - if (propsInLine.length > maximum) { - const name = getPropName(propsInLine[maximum]); + 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({ - 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..7002988721 100644 --- a/tests/lib/rules/jsx-max-props-per-line.js +++ b/tests/lib/rules/jsx-max-props-per-line.js @@ -60,7 +60,38 @@ 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}}] + }, { + code: '', + options: [{maximum: {multi: 2, single: 3}}] + }, { + code: '', + options: [{maximum: {single: 2}}] + }, { + code: [ + '' + ].join('\n'), + options: [{maximum: {multi: 2, single: 1}}] + } + ], invalid: [{ code: ';', @@ -266,5 +297,129 @@ ruleTester.run('jsx-max-props-per-line', rule, { messageId: 'newLine', data: {prop: 'baz'} }] + }, + { + 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'} + }] + }, { + 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'} + }] }] });