UNPKG

2.94 kBJavaScriptView Raw
1/**
2 * @fileoverview Limit maximum of props on a single line in JSX
3 * @author Yannick Croissant
4 */
5
6'use strict';
7
8const docsUrl = require('../util/docsUrl');
9
10// ------------------------------------------------------------------------------
11// Rule Definition
12// ------------------------------------------------------------------------------
13
14module.exports = {
15 meta: {
16 docs: {
17 description: 'Limit maximum of props on a single line in JSX',
18 category: 'Stylistic Issues',
19 recommended: false,
20 url: docsUrl('jsx-max-props-per-line')
21 },
22 fixable: 'code',
23 schema: [{
24 type: 'object',
25 properties: {
26 maximum: {
27 type: 'integer',
28 minimum: 1
29 },
30 when: {
31 type: 'string',
32 enum: ['always', 'multiline']
33 }
34 }
35 }]
36 },
37
38 create(context) {
39 const configuration = context.options[0] || {};
40 const maximum = configuration.maximum || 1;
41 const when = configuration.when || 'always';
42
43 function getPropName(propNode) {
44 if (propNode.type === 'JSXSpreadAttribute') {
45 return context.getSourceCode().getText(propNode.argument);
46 }
47 return propNode.name.name;
48 }
49
50 function generateFixFunction(line, max) {
51 const sourceCode = context.getSourceCode();
52 const output = [];
53 const front = line[0].range[0];
54 const back = line[line.length - 1].range[1];
55 for (let i = 0; i < line.length; i += max) {
56 const nodes = line.slice(i, i + max);
57 output.push(nodes.reduce((prev, curr) => {
58 if (prev === '') {
59 return sourceCode.getText(curr);
60 }
61 return `${prev} ${sourceCode.getText(curr)}`;
62 }, ''));
63 }
64 const code = output.join('\n');
65 return function fix(fixer) {
66 return fixer.replaceTextRange([front, back], code);
67 };
68 }
69
70 return {
71 JSXOpeningElement(node) {
72 if (!node.attributes.length) {
73 return;
74 }
75
76 if (when === 'multiline' && node.loc.start.line === node.loc.end.line) {
77 return;
78 }
79
80 const firstProp = node.attributes[0];
81 const linePartitionedProps = [[firstProp]];
82
83 node.attributes.reduce((last, decl) => {
84 if (last.loc.end.line === decl.loc.start.line) {
85 linePartitionedProps[linePartitionedProps.length - 1].push(decl);
86 } else {
87 linePartitionedProps.push([decl]);
88 }
89 return decl;
90 });
91
92 linePartitionedProps.forEach((propsInLine) => {
93 if (propsInLine.length > maximum) {
94 const name = getPropName(propsInLine[maximum]);
95 context.report({
96 node: propsInLine[maximum],
97 message: `Prop \`${name}\` must be placed on a new line`,
98 fix: generateFixFunction(propsInLine, maximum)
99 });
100 }
101 });
102 }
103 };
104 }
105};