UNPKG

3.65 kBJavaScriptView Raw
1const { fixingNodes } = require('./es-beautifier-common.js');
2
3const create = (context) => {
4 const option = context.options[0] || {
5 allowSingleLine: true,
6 maxLenInSingleLine: 80,
7 };
8 const allowSingleLine = option.allowSingleLine;
9 const maxElements = option.maxElementsInSingleLine;
10 const maxLen = option.maxLenInSingleLine;
11
12 const sourceCode = context.getSourceCode();
13
14 const enterJSXElement = (node) => {
15 if (allowSingleLine &&
16 node.loc.start.line === node.loc.end.line &&
17 (!maxElements || node.elements.length <= maxElements) &&
18 (!maxLen || sourceCode.lines[node.loc.end.line - 1].length < maxLen)) {
19 // we accept one line
20 return;
21 }
22
23 let parent = node.parent;
24 while (parent && parent.loc.start.line === node.loc.start.line) {
25 if (fixingNodes.has(parent)) {
26 // we ignore this time as we are still in the process
27 return;
28 }
29 parent = parent.parent;
30 }
31
32 const children = node.children.filter(x => x.type === 'JSXElement');
33
34 let fixed = false;
35 let prev = null;
36 children.forEach((curr) => {
37 if (prev && prev.loc.end.line === curr.loc.start.line) {
38 context.report({
39 node,
40 message: 'Element in JSX should be on a new line.',
41 loc: curr.loc.start,
42 fix: fixer => fixer.insertTextBefore(curr, '\n'),
43 });
44 fixed = true;
45 }
46 prev = curr;
47 });
48
49 if (children.length) {
50 const firstChild = children[0];
51 const lastChild = children[children.length - 1];
52 if (node.openingElement.loc.end.line === firstChild.loc.start.line) {
53 context.report({
54 node,
55 message: 'Element in JSX should be on a new line.',
56 loc: node.loc.start,
57 fix: fixer => fixer.insertTextAfter(node.openingElement, '\n'),
58 });
59 fixed = true;
60 }
61 if (node.closingElement.loc.start.line === lastChild.loc.end.line) {
62 context.report({
63 node,
64 message: 'Element in JSX should be on a new line.',
65 loc: node.loc.start,
66 fix: fixer => fixer.insertTextBefore(node.closingElement, '\n'),
67 });
68 fixed = true;
69 }
70 }
71
72 const openingParen = sourceCode.getTokenBefore(node.openingElement);
73 if (openingParen &&
74 openingParen.value === '(' &&
75 openingParen.loc.end.line === node.openingElement.loc.start.line) {
76 context.report({
77 node,
78 message: 'Element in JSX should be on a new line.',
79 loc: node.loc.start,
80 fix: fixer => fixer.insertTextBefore(node.openingElement, '\n'),
81 });
82 fixed = true;
83 }
84
85 const closingParen = sourceCode.getTokenAfter(node.closingElement);
86 if (closingParen &&
87 closingParen.value === ')' &&
88 closingParen.loc.start.line === node.closingElement.loc.end.line) {
89 context.report({
90 node,
91 message: 'Element in JSX should be on a new line.',
92 loc: node.loc.end,
93 fix: fixer => fixer.insertTextAfter(node.closingElement, '\n'),
94 });
95 fixed = true;
96 }
97
98 if (fixed) fixingNodes.add(node);
99 };
100
101 return {
102 JSXElement: enterJSXElement,
103 };
104};
105
106module.exports = {
107 meta: {
108 docs: {
109 description: 'enforce multi-line elements in JSX',
110 category: 'Stylistic Issues',
111 },
112 fixable: 'whitespace',
113 schema: [{
114 type: 'object',
115 properties: {
116 allowSingleLine: { type: 'boolean' },
117 maxElementsInSingleLine: { type: 'integer' },
118 maxLenInSingleLine: { type: 'integer' },
119 },
120 additionalProperties: false,
121 }],
122 },
123 create,
124};