eol-last.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /**
  2. * @fileoverview Require or disallow newline at the end of files
  3. * @author Nodeca Team <https://github.com/nodeca>
  4. * @deprecated in ESLint v8.53.0
  5. */
  6. "use strict";
  7. //------------------------------------------------------------------------------
  8. // Rule Definition
  9. //------------------------------------------------------------------------------
  10. /** @type {import('../types').Rule.RuleModule} */
  11. module.exports = {
  12. meta: {
  13. deprecated: {
  14. message: "Formatting rules are being moved out of ESLint core.",
  15. url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
  16. deprecatedSince: "8.53.0",
  17. availableUntil: "11.0.0",
  18. replacedBy: [
  19. {
  20. message:
  21. "ESLint Stylistic now maintains deprecated stylistic core rules.",
  22. url: "https://eslint.style/guide/migration",
  23. plugin: {
  24. name: "@stylistic/eslint-plugin",
  25. url: "https://eslint.style",
  26. },
  27. rule: {
  28. name: "eol-last",
  29. url: "https://eslint.style/rules/eol-last",
  30. },
  31. },
  32. ],
  33. },
  34. type: "layout",
  35. docs: {
  36. description: "Require or disallow newline at the end of files",
  37. recommended: false,
  38. url: "https://eslint.org/docs/latest/rules/eol-last",
  39. },
  40. fixable: "whitespace",
  41. schema: [
  42. {
  43. enum: ["always", "never", "unix", "windows"],
  44. },
  45. ],
  46. messages: {
  47. missing: "Newline required at end of file but not found.",
  48. unexpected: "Newline not allowed at end of file.",
  49. },
  50. },
  51. create(context) {
  52. //--------------------------------------------------------------------------
  53. // Public
  54. //--------------------------------------------------------------------------
  55. return {
  56. Program: function checkBadEOF(node) {
  57. const sourceCode = context.sourceCode,
  58. src = sourceCode.getText(),
  59. lastLine = sourceCode.lines.at(-1),
  60. location = {
  61. column: lastLine.length,
  62. line: sourceCode.lines.length,
  63. },
  64. LF = "\n",
  65. CRLF = `\r${LF}`,
  66. endsWithNewline = src.endsWith(LF);
  67. /*
  68. * Empty source is always valid: No content in file so we don't
  69. * need to lint for a newline on the last line of content.
  70. */
  71. if (!src.length) {
  72. return;
  73. }
  74. let mode = context.options[0] || "always",
  75. appendCRLF = false;
  76. if (mode === "unix") {
  77. // `"unix"` should behave exactly as `"always"`
  78. mode = "always";
  79. }
  80. if (mode === "windows") {
  81. // `"windows"` should behave exactly as `"always"`, but append CRLF in the fixer for backwards compatibility
  82. mode = "always";
  83. appendCRLF = true;
  84. }
  85. if (mode === "always" && !endsWithNewline) {
  86. // File is not newline-terminated, but should be
  87. context.report({
  88. node,
  89. loc: location,
  90. messageId: "missing",
  91. fix(fixer) {
  92. return fixer.insertTextAfterRange(
  93. [0, src.length],
  94. appendCRLF ? CRLF : LF,
  95. );
  96. },
  97. });
  98. } else if (mode === "never" && endsWithNewline) {
  99. const secondLastLine = sourceCode.lines.at(-2);
  100. // File is newline-terminated, but shouldn't be
  101. context.report({
  102. node,
  103. loc: {
  104. start: {
  105. line: sourceCode.lines.length - 1,
  106. column: secondLastLine.length,
  107. },
  108. end: { line: sourceCode.lines.length, column: 0 },
  109. },
  110. messageId: "unexpected",
  111. fix(fixer) {
  112. const finalEOLs = /(?:\r?\n)+$/u,
  113. match = finalEOLs.exec(sourceCode.text),
  114. start = match.index,
  115. end = sourceCode.text.length;
  116. return fixer.replaceTextRange([start, end], "");
  117. },
  118. });
  119. }
  120. },
  121. };
  122. },
  123. };