diff --git a/lib/rules/max-len.js b/lib/rules/max-len.js index b29099ed4c4..82229c3be48 100644 --- a/lib/rules/max-len.js +++ b/lib/rules/max-len.js @@ -183,6 +183,21 @@ module.exports = { (end.line > lineNumber || (end.line === lineNumber && end.column === line.length)); } + /** + * Check if a node is a JSXEmptyExpression contained in a single line JSXExpressionContainer. + * @param {ASTNode} node A node to check. + * @returns {boolean} True if the node is a JSXEmptyExpression contained in a single line JSXExpressionContainer. + */ + function isJSXEmptyExpressionInSingleLineContainer(node) { + if (!node || !node.parent || node.type !== "JSXEmptyExpression" || node.parent.type !== "JSXExpressionContainer") { + return false; + } + + const parent = node.parent; + + return parent.loc.start.line === parent.loc.end.line; + } + /** * Gets the line after the comment and any remaining trailing whitespace is * stripped. @@ -252,6 +267,33 @@ module.exports = { return acc; } + /** + * Returns an array of all comments in the source code. + * If the element in the array is a JSXEmptyExpression contained with a single line JSXExpressionContainer, + * the element is changed with JSXExpressionContainer node. + * @returns {ASTNode[]} An array of comment nodes + */ + function getAllComments() { + const comments = []; + + sourceCode.getAllComments() + .forEach(commentNode => { + const containingNode = sourceCode.getNodeByRangeIndex(commentNode.range[0]); + + if (isJSXEmptyExpressionInSingleLineContainer(containingNode)) { + + // push a unique node only + if (comments[comments.length - 1] !== containingNode.parent) { + comments.push(containingNode.parent); + } + } else { + comments.push(commentNode); + } + }); + + return comments; + } + /** * Check the program for max length * @param {ASTNode} node Node to examine @@ -264,7 +306,7 @@ module.exports = { const lines = sourceCode.lines, // list of comments to ignore - comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? sourceCode.getAllComments() : []; + comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? getAllComments() : []; // we iterate over comments in parallel with the lines let commentsIndex = 0; diff --git a/tests/lib/rules/max-len.js b/tests/lib/rules/max-len.js index 99822ccaef0..f6296b636b9 100644 --- a/tests/lib/rules/max-len.js +++ b/tests/lib/rules/max-len.js @@ -195,6 +195,140 @@ ruleTester.run("max-len", rule, { { code: "\tfoo", options: [4, { tabWidth: 0 }] + }, + + // https://github.com/eslint/eslint/issues/12213 + { + code: "var jsx = (<>\n" + + " { /* this line has 38 characters */}\n" + + ")", + options: [15, { comments: 38 }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + "\t\t{ /* this line has 40 characters */}\n" + + ")", + options: [15, 4, { comments: 44 }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " <> text { /* this line has 49 characters */}\n" + + ")", + options: [13, { ignoreComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this line has 44 characters */}\n" + + ")", + options: [44, { comments: 37 }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this line has 44 characters */}\n" + + ")", + options: [37, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = ;", + options: [57], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = ;", + options: [57], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = ;", + options: [50], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " <> {/* this line with two separate comments */} {/* have 80 characters */}\n" + + ")", + options: [80], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this line with two separate comments */} {/* have 80 characters */}\n" + + ")", + options: [37, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this line with two separate comments */} {/* have 80 characters */}\n" + + ")", + options: [37, { ignoreComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this line with two separate comments */} {/* have > 80 characters */ /* another comment in same braces */}\n" + + ")", + options: [37, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this line with two separate comments */} {/* have > 80 characters */ /* another comment in same braces */}\n" + + ")", + options: [37, { ignoreComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {/*\n" + + " this line has 34 characters\n" + + " */}\n" + + ")", + options: [33, { comments: 34 }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {/*\n" + + " this line has 34 characters\n" + + " */}\n" + + ")", + options: [33, { ignoreComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {a & b /* this line has 34 characters\n" + + " */}\n" + + ")", + options: [33, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } } + }, + { + code: "var jsx = (<>\n" + + " {a & b /* this line has 34 characters\n" + + " */}\n" + + ")", + options: [33, { ignoreComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } } } ], @@ -650,6 +784,321 @@ ruleTester.run("max-len", rule, { column: 1 } ] + }, + + // https://github.com/eslint/eslint/issues/12213 + { + code: "var jsx = (<>\n" + + " { /* this line has 38 characters */}\n" + + ")", + options: [15, { comments: 37 }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "maxComment", + data: { lineLength: 38, maxCommentLength: 37 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + "\t\t{ /* this line has 40 characters */}\n" + + ")", + options: [15, 4, { comments: 40 }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "maxComment", + data: { lineLength: 44, maxCommentLength: 40 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + "{ 38/* this line has 38 characters */}\n" + + ")", + options: [15, { comments: 38 }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 38, maxLength: 15 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + "{ 38/* this line has 38 characters */}\n" + + ")", + options: [37, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 38, maxLength: 37 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + "{ 38/* this line has 38 characters */}\n" + + ")", + options: [37, { ignoreComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 38, maxLength: 37 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + " <> 50 { 50/* this line has 50 characters */}\n" + + ")", + options: [49, { comments: 100 }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 50, maxLength: 49 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 44 characters */}\n" + + " <> {/* this line has 44 characters */}\n" + + ")", + options: [37, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 44, maxLength: 37 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = ;", + options: [56], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 57, maxLength: 56 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = ;", + options: [56], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 57, maxLength: 56 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = ;", + options: [55, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 56, maxLength: 55 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = ;", + options: [30, { comments: 44 }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 51, maxLength: 30 }, + type: "Program", + line: 3, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this line with two separate comments */} {/* have 80 characters */}\n" + + ")", + options: [79], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 80, maxLength: 79 }, + type: "Program", + line: 3, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + " <> {/* this line with two separate comments */} {/* have 87 characters */} <> \n" + + ")", + options: [85, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 87, maxLength: 85 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this line with two separate comments */} {/* have 87 characters */} <> \n" + + ")", + options: [37, { ignoreComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 87, maxLength: 37 }, + type: "Program", + line: 3, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this line with two separate comments */} {/* have > 80 characters */ /* another comment in same braces */}\n" + + ")", + options: [37], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 119, maxLength: 37 }, + type: "Program", + line: 3, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this is not treated as a comment */ a & b} {/* trailing */ /* comments */}\n" + + ")", + options: [37, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 55, maxLength: 37 }, + type: "Program", + line: 3, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + " {/* this line has 37 characters */}\n" + + " <> {/* this is not treated as a comment */ a & b} {/* trailing */ /* comments */}\n" + + ")", + options: [37, { ignoreComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 55, maxLength: 37 }, + type: "Program", + line: 3, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + "12345678901234{/*\n" + + "*/}\n" + + ")", + options: [14, { ignoreTrailingComments: true }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 15, maxLength: 14 }, + type: "Program", + line: 2, + column: 1 + } + ] + }, + { + code: "var jsx = (<>\n" + + "{/*\n" + + "this line has 31 characters */}\n" + + ")", + options: [30, { comments: 100 }], + parserOptions: { ecmaFeatures: { jsx: true } }, + errors: [ + { + messageId: "max", + data: { lineLength: 31, maxLength: 30 }, + type: "Program", + line: 3, + column: 1 + } + ] } ] });