source: imaps-frontend/node_modules/eslint-plugin-react/lib/rules/jsx-curly-newline.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 6.0 KB
Line 
1/**
2 * @fileoverview enforce consistent line breaks inside jsx curly
3 */
4
5'use strict';
6
7const docsUrl = require('../util/docsUrl');
8const eslintUtil = require('../util/eslint');
9const report = require('../util/report');
10
11const getSourceCode = eslintUtil.getSourceCode;
12const getText = eslintUtil.getText;
13
14// ------------------------------------------------------------------------------
15// Rule Definition
16// ------------------------------------------------------------------------------
17
18function getNormalizedOption(context) {
19 const rawOption = context.options[0] || 'consistent';
20
21 if (rawOption === 'consistent') {
22 return {
23 multiline: 'consistent',
24 singleline: 'consistent',
25 };
26 }
27
28 if (rawOption === 'never') {
29 return {
30 multiline: 'forbid',
31 singleline: 'forbid',
32 };
33 }
34
35 return {
36 multiline: rawOption.multiline || 'consistent',
37 singleline: rawOption.singleline || 'consistent',
38 };
39}
40
41const messages = {
42 expectedBefore: 'Expected newline before \'}\'.',
43 expectedAfter: 'Expected newline after \'{\'.',
44 unexpectedBefore: 'Unexpected newline before \'}\'.',
45 unexpectedAfter: 'Unexpected newline after \'{\'.',
46};
47
48/** @type {import('eslint').Rule.RuleModule} */
49module.exports = {
50 meta: {
51 type: 'layout',
52
53 docs: {
54 description: 'Enforce consistent linebreaks in curly braces in JSX attributes and expressions',
55 category: 'Stylistic Issues',
56 recommended: false,
57 url: docsUrl('jsx-curly-newline'),
58 },
59
60 fixable: 'whitespace',
61
62 schema: [
63 {
64 anyOf: [
65 {
66 enum: ['consistent', 'never'],
67 },
68 {
69 type: 'object',
70 properties: {
71 singleline: { enum: ['consistent', 'require', 'forbid'] },
72 multiline: { enum: ['consistent', 'require', 'forbid'] },
73 },
74 additionalProperties: false,
75 },
76 ],
77 },
78 ],
79
80 messages,
81 },
82
83 create(context) {
84 const sourceCode = getSourceCode(context);
85 const option = getNormalizedOption(context);
86
87 // ----------------------------------------------------------------------
88 // Helpers
89 // ----------------------------------------------------------------------
90
91 /**
92 * Determines whether two adjacent tokens are on the same line.
93 * @param {Object} left - The left token object.
94 * @param {Object} right - The right token object.
95 * @returns {boolean} Whether or not the tokens are on the same line.
96 */
97 function isTokenOnSameLine(left, right) {
98 return left.loc.end.line === right.loc.start.line;
99 }
100
101 /**
102 * Determines whether there should be newlines inside curlys
103 * @param {ASTNode} expression The expression contained in the curlys
104 * @param {boolean} hasLeftNewline `true` if the left curly has a newline in the current code.
105 * @returns {boolean} `true` if there should be newlines inside the function curlys
106 */
107 function shouldHaveNewlines(expression, hasLeftNewline) {
108 const isMultiline = expression.loc.start.line !== expression.loc.end.line;
109
110 switch (isMultiline ? option.multiline : option.singleline) {
111 case 'forbid': return false;
112 case 'require': return true;
113 case 'consistent':
114 default: return hasLeftNewline;
115 }
116 }
117
118 /**
119 * Validates curlys
120 * @param {Object} curlys An object with keys `leftParen` for the left paren token, and `rightParen` for the right paren token
121 * @param {ASTNode} expression The expression inside the curly
122 * @returns {void}
123 */
124 function validateCurlys(curlys, expression) {
125 const leftCurly = curlys.leftCurly;
126 const rightCurly = curlys.rightCurly;
127 const tokenAfterLeftCurly = sourceCode.getTokenAfter(leftCurly);
128 const tokenBeforeRightCurly = sourceCode.getTokenBefore(rightCurly);
129 const hasLeftNewline = !isTokenOnSameLine(leftCurly, tokenAfterLeftCurly);
130 const hasRightNewline = !isTokenOnSameLine(tokenBeforeRightCurly, rightCurly);
131 const needsNewlines = shouldHaveNewlines(expression, hasLeftNewline);
132
133 if (hasLeftNewline && !needsNewlines) {
134 report(context, messages.unexpectedAfter, 'unexpectedAfter', {
135 node: leftCurly,
136 fix(fixer) {
137 return getText(context)
138 .slice(leftCurly.range[1], tokenAfterLeftCurly.range[0])
139 .trim()
140 ? null // If there is a comment between the { and the first element, don't do a fix.
141 : fixer.removeRange([leftCurly.range[1], tokenAfterLeftCurly.range[0]]);
142 },
143 });
144 } else if (!hasLeftNewline && needsNewlines) {
145 report(context, messages.expectedAfter, 'expectedAfter', {
146 node: leftCurly,
147 fix: (fixer) => fixer.insertTextAfter(leftCurly, '\n'),
148 });
149 }
150
151 if (hasRightNewline && !needsNewlines) {
152 report(context, messages.unexpectedBefore, 'unexpectedBefore', {
153 node: rightCurly,
154 fix(fixer) {
155 return getText(context)
156 .slice(tokenBeforeRightCurly.range[1], rightCurly.range[0])
157 .trim()
158 ? null // If there is a comment between the last element and the }, don't do a fix.
159 : fixer.removeRange([
160 tokenBeforeRightCurly.range[1],
161 rightCurly.range[0],
162 ]);
163 },
164 });
165 } else if (!hasRightNewline && needsNewlines) {
166 report(context, messages.expectedBefore, 'expectedBefore', {
167 node: rightCurly,
168 fix: (fixer) => fixer.insertTextBefore(rightCurly, '\n'),
169 });
170 }
171 }
172
173 // ----------------------------------------------------------------------
174 // Public
175 // ----------------------------------------------------------------------
176
177 return {
178 JSXExpressionContainer(node) {
179 const curlyTokens = {
180 leftCurly: sourceCode.getFirstToken(node),
181 rightCurly: sourceCode.getLastToken(node),
182 };
183 validateCurlys(curlyTokens, node.expression);
184 },
185 };
186 },
187};
Note: See TracBrowser for help on using the repository browser.