UNPKG

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