UNPKG

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