diff --git a/README.md b/README.md index 7993888c70..f43bc2932c 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,6 @@ Finally, enable all of the rules that you would like to use. Use [our preset](# * [react/self-closing-comp](docs/rules/self-closing-comp.md): Prevent extra closing tags for components without children * [react/sort-comp](docs/rules/sort-comp.md): Enforce component methods order * [react/sort-prop-types](docs/rules/sort-prop-types.md): Enforce propTypes declarations alphabetical sorting -* [react/wrap-multilines](docs/rules/wrap-multilines.md): Prevent missing parentheses around multilines JSX (fixable) ## JSX-specific rules @@ -129,6 +128,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](# * [react/jsx-space-before-closing](docs/rules/jsx-space-before-closing.md): Validate spacing before closing bracket in JSX (fixable) * [react/jsx-uses-react](docs/rules/jsx-uses-react.md): Prevent React to be incorrectly marked as unused * [react/jsx-uses-vars](docs/rules/jsx-uses-vars.md): Prevent variables used in JSX to be incorrectly marked as unused +* [react/jsx-wrap-multilines](docs/rules/jsx-wrap-multilines.md): Prevent missing parentheses around multilines JSX (fixable) ## React Native rules diff --git a/docs/rules/wrap-multilines.md b/docs/rules/jsx-wrap-multilines.md similarity index 93% rename from docs/rules/wrap-multilines.md rename to docs/rules/jsx-wrap-multilines.md index b24e892b97..3179f8cca3 100644 --- a/docs/rules/wrap-multilines.md +++ b/docs/rules/jsx-wrap-multilines.md @@ -1,4 +1,4 @@ -# Prevent missing parentheses around multiline JSX (wrap-multilines) +# Prevent missing parentheses around multiline JSX (jsx-wrap-multilines) Wrapping multiline JSX in parentheses can improve readability and/or convenience. It optionally takes a second parameter in the form of an object, containing places to apply the rule. By default, `"declaration"`, `"assignment"`, and `"return"` syntax is checked, but these can be explicitly disabled. Any syntax type missing in the object will follow the default behavior (become enabled). diff --git a/index.js b/index.js index ee58d09f25..a28494f79e 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ var rules = { 'prop-types': require('./lib/rules/prop-types'), 'display-name': require('./lib/rules/display-name'), 'wrap-multilines': require('./lib/rules/wrap-multilines'), + 'jsx-wrap-multilines': require('./lib/rules/jsx-wrap-multilines'), 'self-closing-comp': require('./lib/rules/self-closing-comp'), 'no-comment-textnodes': require('./lib/rules/no-comment-textnodes'), 'jsx-no-comment-textnodes': require('./lib/rules/jsx-no-comment-textnodes'), diff --git a/lib/rules/jsx-wrap-multilines.js b/lib/rules/jsx-wrap-multilines.js new file mode 100644 index 0000000000..a28b9a7341 --- /dev/null +++ b/lib/rules/jsx-wrap-multilines.js @@ -0,0 +1,103 @@ +/** + * @fileoverview Prevent missing parentheses around multilines JSX + * @author Yannick Croissant + */ +'use strict'; + +// ------------------------------------------------------------------------------ +// Constants +// ------------------------------------------------------------------------------ + +var DEFAULTS = { + declaration: true, + assignment: true, + return: true +}; + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = function(context) { + + var sourceCode = context.getSourceCode(); + + function isParenthesised(node) { + var previousToken = sourceCode.getTokenBefore(node); + var nextToken = sourceCode.getTokenAfter(node); + + return previousToken && nextToken && + previousToken.value === '(' && previousToken.range[1] <= node.range[0] && + nextToken.value === ')' && nextToken.range[0] >= node.range[1]; + } + + function isMultilines(node) { + return node.loc.start.line !== node.loc.end.line; + } + + function check(node) { + if (!node || node.type !== 'JSXElement') { + return; + } + + if (!isParenthesised(node) && isMultilines(node)) { + context.report({ + node: node, + message: 'Missing parentheses around multilines JSX', + fix: function(fixer) { + return fixer.replaceText(node, '(' + sourceCode.getText(node) + ')'); + } + }); + } + } + + function isEnabled(type) { + var userOptions = context.options[0] || {}; + if (({}).hasOwnProperty.call(userOptions, type)) { + return userOptions[type]; + } + return DEFAULTS[type]; + } + + // -------------------------------------------------------------------------- + // Public + // -------------------------------------------------------------------------- + + return { + + VariableDeclarator: function(node) { + if (isEnabled('declaration')) { + check(node.init); + } + }, + + AssignmentExpression: function(node) { + if (isEnabled('assignment')) { + check(node.right); + } + }, + + ReturnStatement: function(node) { + if (isEnabled('return')) { + check(node.argument); + } + } + }; + +}; + +module.exports.schema = [{ + type: 'object', + properties: { + declaration: { + type: 'boolean' + }, + assignment: { + type: 'boolean' + }, + return: { + type: 'boolean' + } + }, + additionalProperties: false +}]; diff --git a/lib/rules/wrap-multilines.js b/lib/rules/wrap-multilines.js index a28b9a7341..f1266e2e87 100644 --- a/lib/rules/wrap-multilines.js +++ b/lib/rules/wrap-multilines.js @@ -1,89 +1,32 @@ /** * @fileoverview Prevent missing parentheses around multilines JSX * @author Yannick Croissant + * @deprecated */ 'use strict'; -// ------------------------------------------------------------------------------ -// Constants -// ------------------------------------------------------------------------------ - -var DEFAULTS = { - declaration: true, - assignment: true, - return: true -}; - // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ -module.exports = function(context) { - - var sourceCode = context.getSourceCode(); +var util = require('util'); +var jsxWrapMultilines = require('./jsx-wrap-multilines'); +var isWarnedForDeprecation = false; - function isParenthesised(node) { - var previousToken = sourceCode.getTokenBefore(node); - var nextToken = sourceCode.getTokenAfter(node); - - return previousToken && nextToken && - previousToken.value === '(' && previousToken.range[1] <= node.range[0] && - nextToken.value === ')' && nextToken.range[0] >= node.range[1]; - } - - function isMultilines(node) { - return node.loc.start.line !== node.loc.end.line; - } - - function check(node) { - if (!node || node.type !== 'JSXElement') { - return; - } - - if (!isParenthesised(node) && isMultilines(node)) { - context.report({ - node: node, - message: 'Missing parentheses around multilines JSX', - fix: function(fixer) { - return fixer.replaceText(node, '(' + sourceCode.getText(node) + ')'); - } - }); - } - } - - function isEnabled(type) { - var userOptions = context.options[0] || {}; - if (({}).hasOwnProperty.call(userOptions, type)) { - return userOptions[type]; - } - return DEFAULTS[type]; - } - - // -------------------------------------------------------------------------- - // Public - // -------------------------------------------------------------------------- - - return { - - VariableDeclarator: function(node) { - if (isEnabled('declaration')) { - check(node.init); - } - }, - - AssignmentExpression: function(node) { - if (isEnabled('assignment')) { - check(node.right); +module.exports = function(context) { + return util._extend(jsxWrapMultilines(context), { + Program: function() { + if (isWarnedForDeprecation || /\=-(f|-format)=/.test(process.argv.join('='))) { + return; } - }, - ReturnStatement: function(node) { - if (isEnabled('return')) { - check(node.argument); - } + /* eslint-disable no-console */ + console.log('The react/wrap-multilines rule is deprecated. Please ' + + 'use the react/jsx-wrap-multilines rule instead.'); + /* eslint-enable no-console */ + isWarnedForDeprecation = true; } - }; - + }); }; module.exports.schema = [{ diff --git a/tests/lib/rules/wrap-multilines.js b/tests/lib/rules/jsx-wrap-multilines.js similarity index 97% rename from tests/lib/rules/wrap-multilines.js rename to tests/lib/rules/jsx-wrap-multilines.js index e169ff736d..8fe41fd7a8 100644 --- a/tests/lib/rules/wrap-multilines.js +++ b/tests/lib/rules/jsx-wrap-multilines.js @@ -8,7 +8,7 @@ // Requirements // ------------------------------------------------------------------------------ -var rule = require('../../../lib/rules/wrap-multilines'); +var rule = require('../../../lib/rules/jsx-wrap-multilines'); var RuleTester = require('eslint').RuleTester; var parserOptions = { @@ -78,7 +78,7 @@ var ASSIGNMENT_NO_PAREN = '\ // ------------------------------------------------------------------------------ var ruleTester = new RuleTester(); -ruleTester.run('wrap-multilines', rule, { +ruleTester.run('jsx-wrap-multilines', rule, { valid: [ {