diff --git a/lib/rules/multiline-comment-style.js b/lib/rules/multiline-comment-style.js index cccc841cd867..8cf497b786e1 100644 --- a/lib/rules/multiline-comment-style.js +++ b/lib/rules/multiline-comment-style.js @@ -18,13 +18,20 @@ module.exports = { recommended: false }, fixable: "whitespace", - schema: [{ enum: ["starred-block", "separate-lines"] }] + schema: [{ enum: ["starred-block", "separate-lines", "bare-block"] }] }, create(context) { const sourceCode = context.getSourceCode(); const option = context.options[0] || "starred-block"; + const EXPECTED_BLOCK_ERROR = "Expected a block comment instead of consecutive line comments."; + const START_NEWLINE_ERROR = "Expected a linebreak after '/*'."; + const END_NEWLINE_ERROR = "Expected a linebreak before '*/'."; + const MISSING_STAR_ERROR = "Expected a '*' at the start of this line."; + const ALIGNMENT_ERROR = "Expected this line to be aligned with the start of the comment."; + const EXPECTED_LINES_ERROR = "Expected multiple line comments instead of a block comment."; + //---------------------------------------------------------------------- // Helpers //---------------------------------------------------------------------- @@ -56,6 +63,32 @@ module.exports = { return `\n${starredLines.join("\n")}\n${initialOffset} `; } + /** + * Converts a comment into separate-line form + * @param {Token} firstComment The first comment of the group being converted + * @param {string[]} commentLinesList A list of lines to appear in the new starred-block comment + * @returns {string} A representation of the comment value in separate-line form + */ + function convertToSeparateLines(firstComment, commentLinesList) { + const initialOffset = sourceCode.text.slice(firstComment.range[0] - firstComment.loc.start.column, firstComment.range[0]); + const separateLines = commentLinesList.map(line => `// ${line.trim()}`); + + return separateLines.join(`\n${initialOffset}`); + } + + /** + * Converts a comment into bare-block form + * @param {Token} firstComment The first comment of the group being converted + * @param {string[]} commentLinesList A list of lines to appear in the new starred-block comment + * @returns {string} A representation of the comment value in bare-block form + */ + function convertToBlock(firstComment, commentLinesList) { + const initialOffset = sourceCode.text.slice(firstComment.range[0] - firstComment.loc.start.column, firstComment.range[0]); + const blockLines = commentLinesList.map(line => line.trim()); + + return `/* ${blockLines.join(`\n${initialOffset}`)} */`; + } + /** * Each method checks a group of comments to see if it's valid according to the given option. * @param {Token[]} commentGroup A list of comments that appear together. This will either contain a single @@ -76,7 +109,7 @@ module.exports = { start: commentGroup[0].loc.start, end: commentGroup[commentGroup.length - 1].loc.end }, - message: "Expected a block comment instead of consecutive line comments.", + message: EXPECTED_BLOCK_ERROR, fix(fixer) { return fixer.replaceTextRange( [commentGroup[0].range[0], commentGroup[commentGroup.length - 1].range[1]], @@ -97,7 +130,7 @@ module.exports = { start: block.loc.start, end: { line: block.loc.start.line, column: block.loc.start.column + 2 } }, - message: "Expected a linebreak after '/*'.", + message: START_NEWLINE_ERROR, fix: fixer => fixer.insertTextAfterRange([start, start + 2], `\n${expectedLinePrefix}`) }); } @@ -108,7 +141,7 @@ module.exports = { start: { line: block.loc.end.line, column: block.loc.end.column - 2 }, end: block.loc.end }, - message: "Expected a linebreak before '*/'.", + message: END_NEWLINE_ERROR, fix: fixer => fixer.replaceTextRange([block.range[1] - 2, block.range[1]], `\n${expectedLinePrefix}/`) }); } @@ -124,8 +157,8 @@ module.exports = { end: { line: lineNumber, column: sourceCode.lines[lineNumber - 1].length } }, message: /^\s*\*/.test(lineText) - ? "Expected this line to be aligned with the start of the comment." - : "Expected a '*' at the start of this line.", + ? ALIGNMENT_ERROR + : MISSING_STAR_ERROR, fix(fixer) { // TODO: Make this more readable, possibly by splitting it into two separate cases. @@ -140,9 +173,44 @@ module.exports = { } } }, - "separate-lines"() { + "separate-lines"(commentGroup) { // TODO + if (commentGroup[0].type === "Block") { + const block = commentGroup[0]; + + context.report({ + loc: { + start: block.loc.start, + end: { line: block.loc.start.line, column: block.loc.start.column + 2 } + }, + message: EXPECTED_LINES_ERROR, + fix(fixer) { + const commentLines = getCommentLines(commentGroup).filter(line => line.trim()); + + return fixer.replaceTextRange([block.range[0], block.range[1]], convertToSeparateLines(block, commentLines)); + } + }); + } + }, + "bare-block"(commentGroup) { + let commentLines = getCommentLines(commentGroup); + + if (commentGroup[0].type === "Line" && commentLines.length > 1) { + + context.report({ + loc: { + start: commentGroup[0].loc.start, + end: commentGroup[commentGroup.length - 1].loc.end + }, + message: EXPECTED_BLOCK_ERROR, + fix(fixer) { + commentLines = commentLines.filter(line => line.trim()); + + return fixer.replaceTextRange([commentGroup[0].range[0], commentGroup[commentGroup.length - 1].range[1]], convertToBlock(commentGroup[0], commentLines)); + } + }); + } } }; diff --git a/tests/lib/rules/multiline-comment-style.js b/tests/lib/rules/multiline-comment-style.js index 70f6ea9f7b2d..c40d109e2290 100644 --- a/tests/lib/rules/multiline-comment-style.js +++ b/tests/lib/rules/multiline-comment-style.js @@ -339,6 +339,20 @@ ruleTester.run("multiline-comment-style", rule, { `, options: ["separate-lines"], errors: [{ message: EXPECTED_LINES_ERROR, line: 2 }] + }, + + // TODO: add "bare-block" option + { + code: ` + // foo + // bar + `, + output: ` + /* foo + bar */ + `, + options: ["bare-block"], + errors: [{ message: EXPECTED_BLOCK_ERROR, line: 2 }] } ] });