diff --git a/src/parser.ts b/src/parser.ts index c7ee54d..90924e1 100755 --- a/src/parser.ts +++ b/src/parser.ts @@ -3,6 +3,7 @@ import { addStarsToTheBeginningOfTheLines, convertToModernType, formatType, + detectEndOfLine, } from "./utils"; import { DESCRIPTION } from "./tags"; import { @@ -34,6 +35,10 @@ export const getParser = (parser: Parser["parse"]) => return ast; } + const eol = + options.endOfLine === "auto" ? detectEndOfLine(text) : options.endOfLine; + options = { ...options, endOfLine: "lf" }; + /** * Control order of tags by weights. Smaller value brings tag higher. * @@ -55,7 +60,10 @@ export const getParser = (parser: Parser["parse"]) => /** Issue: https://github.com/hosseinmd/prettier-plugin-jsdoc/issues/18 */ comment.value = comment.value.replace(/^([*]+)/g, "*"); - const commentString = `/*${comment.value}*/`; + // Create the full comment string with line ends normalized to \n + // This means that all following code can assume \n and should only use + // \n. + const commentString = `/*${comment.value.replace(/\r\n?/g, "\n")}*/`; /** * Check if this comment block is a JSDoc. Based on: @@ -152,7 +160,7 @@ export const getParser = (parser: Parser["parse"]) => description = description .trim() .replace(/[ \t]*Default is `.*`\.?$/, ""); - if (description && !/[.\r\n]$/.test(description)) { + if (description && !/[.\n]$/.test(description)) { description += "."; } description += ` Default is \`${_default}\``; @@ -229,6 +237,12 @@ export const getParser = (parser: Parser["parse"]) => if (comment.value) { comment.value = addStarsToTheBeginningOfTheLines(comment.value); } + + if (eol === "cr") { + comment.value = comment.value.replace(/\n/g, "\r"); + } else if (eol === "crlf") { + comment.value = comment.value.replace(/\n/g, "\r\n"); + } }); ast.comments = ast.comments.filter( diff --git a/src/utils.ts b/src/utils.ts index 96255dc..1b6b620 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -145,9 +145,46 @@ function capitalizer(str: string): string { return str[0].toUpperCase() + str.slice(1); } +/** + * Detects the line ends of the given text. + * + * If multiple line ends are used, the most common one will be returned. + * + * If the given text is a single line, "lf" will be returned. + * + * @param text + */ +function detectEndOfLine(text: string): "cr" | "crlf" | "lf" { + const counter = { + "\r": 0, + "\r\n": 0, + "\n": 0, + }; + + const lineEndPattern = /\r\n?|\n/g; + let m; + while ((m = lineEndPattern.exec(text))) { + counter[m[0] as keyof typeof counter]++; + } + + const cr = counter["\r"]; + const crlf = counter["\r\n"]; + const lf = counter["\n"]; + const max = Math.max(cr, crlf, lf); + + if (lf === max) { + return "lf"; + } else if (crlf === max) { + return "crlf"; + } else { + return "cr"; + } +} + export { convertToModernType, formatType, addStarsToTheBeginningOfTheLines, capitalizer, + detectEndOfLine, }; diff --git a/tests/main.test.js b/tests/main.test.js index 4193827..75ff92b 100755 --- a/tests/main.test.js +++ b/tests/main.test.js @@ -442,3 +442,36 @@ test("Format rest parameters properly", () => { expect(result).toMatchSnapshot(); }); + +test("Line ends", () => { + const text = ` + /** + * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + * @param {Object} paramName param description that goes on and on and on until it will need to be wrapped + * + */ + function a(){}`; + const formatted = `/** + * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + * tempor incididunt ut labore et dolore magna aliqua. + * + * @param {Object} paramName Param description that goes on and on and on + * until it will need to be wrapped + */ +function a() {} +`; + + const text_crlf = text.replace(/\n/g, "\r\n"); + const text_lf = text; + const formatted_crlf = formatted.replace(/\n/g, "\r\n"); + const formatted_lf = formatted; + + expect(subject(text_lf, { endOfLine: "crlf" })).toEqual(formatted_crlf); + expect(subject(text_lf, { endOfLine: "lf" })).toEqual(formatted_lf); + + expect(subject(text_crlf, { endOfLine: "crlf" })).toEqual(formatted_crlf); + expect(subject(text_crlf, { endOfLine: "lf" })).toEqual(formatted_lf); + + expect(subject(text_lf, { endOfLine: "auto" })).toEqual(formatted_lf); + expect(subject(text_crlf, { endOfLine: "auto" })).toEqual(formatted_crlf); +});