| /** |
| * @fileoverview Limit maximum of props on a single line in JSX |
| * @author Yannick Croissant |
| */ |
| |
| 'use strict'; |
| |
| const docsUrl = require('../util/docsUrl'); |
| |
| // ------------------------------------------------------------------------------ |
| // Rule Definition |
| // ------------------------------------------------------------------------------ |
| |
| module.exports = { |
| meta: { |
| docs: { |
| description: 'Limit maximum of props on a single line in JSX', |
| category: 'Stylistic Issues', |
| recommended: false, |
| url: docsUrl('jsx-max-props-per-line') |
| }, |
| fixable: 'code', |
| schema: [{ |
| type: 'object', |
| properties: { |
| maximum: { |
| type: 'integer', |
| minimum: 1 |
| }, |
| when: { |
| type: 'string', |
| enum: ['always', 'multiline'] |
| } |
| } |
| }] |
| }, |
| |
| create(context) { |
| const configuration = context.options[0] || {}; |
| const maximum = configuration.maximum || 1; |
| const when = configuration.when || 'always'; |
| |
| function getPropName(propNode) { |
| if (propNode.type === 'JSXSpreadAttribute') { |
| return context.getSourceCode().getText(propNode.argument); |
| } |
| return propNode.name.name; |
| } |
| |
| function generateFixFunction(line, max) { |
| const sourceCode = context.getSourceCode(); |
| 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) => { |
| if (prev === '') { |
| return sourceCode.getText(curr); |
| } |
| return `${prev} ${sourceCode.getText(curr)}`; |
| }, '')); |
| } |
| const code = output.join('\n'); |
| return function fix(fixer) { |
| return fixer.replaceTextRange([front, back], code); |
| }; |
| } |
| |
| return { |
| JSXOpeningElement(node) { |
| if (!node.attributes.length) { |
| return; |
| } |
| |
| if (when === 'multiline' && node.loc.start.line === node.loc.end.line) { |
| return; |
| } |
| |
| const firstProp = node.attributes[0]; |
| const linePartitionedProps = [[firstProp]]; |
| |
| node.attributes.reduce((last, decl) => { |
| if (last.loc.end.line === decl.loc.start.line) { |
| linePartitionedProps[linePartitionedProps.length - 1].push(decl); |
| } else { |
| linePartitionedProps.push([decl]); |
| } |
| return decl; |
| }); |
| |
| linePartitionedProps.forEach((propsInLine) => { |
| if (propsInLine.length > maximum) { |
| const name = getPropName(propsInLine[maximum]); |
| context.report({ |
| node: propsInLine[maximum], |
| message: `Prop \`${name}\` must be placed on a new line`, |
| fix: generateFixFunction(propsInLine, maximum) |
| }); |
| } |
| }); |
| } |
| }; |
| } |
| }; |