From 06adff2d1a254cc4623d64765a142c15e28f0414 Mon Sep 17 00:00:00 2001
From: Eliaztray <944126009@qq.com>
Date: Wed, 12 Jun 2019 00:02:46 +0800
Subject: [PATCH] feat: Add autofix to max-empty-lines
---
lib/rules/max-empty-lines/__tests__/index.js | 64 ++++++++++++++
lib/rules/max-empty-lines/index.js | 88 +++++++++++++++++++-
2 files changed, 151 insertions(+), 1 deletion(-)
diff --git a/lib/rules/max-empty-lines/__tests__/index.js b/lib/rules/max-empty-lines/__tests__/index.js
index 51776dd32e..e5ea677b8f 100644
--- a/lib/rules/max-empty-lines/__tests__/index.js
+++ b/lib/rules/max-empty-lines/__tests__/index.js
@@ -6,6 +6,7 @@ const { messages, ruleName } = rule;
testRule(rule, {
ruleName,
config: [0],
+ fix: true,
accept: [
{
@@ -15,6 +16,7 @@ testRule(rule, {
reject: [
{
code: "\na {}",
+ fixed: "a {}",
message: messages.expected(0),
line: 1,
column: 1
@@ -25,6 +27,7 @@ testRule(rule, {
testRule(rule, {
ruleName,
config: [1],
+ fix: true,
accept: [
{
@@ -68,60 +71,70 @@ testRule(rule, {
reject: [
{
code: "\n\na {}",
+ fixed: "\na {}",
message: messages.expected(1),
line: 2,
column: 1
},
{
code: "\r\n\r\na {}",
+ fixed: "\r\na {}",
message: messages.expected(1),
line: 2,
column: 1
},
{
code: "a {}\n\n",
+ fixed: "a {}\n",
message: messages.expected(1),
line: 3,
column: 1
},
{
code: "a {}\r\n\r\n",
+ fixed: "a {}\r\n",
message: messages.expected(1),
line: 3,
column: 1
},
{
code: "a {}\n\n\nb {}",
+ fixed: "a {}\n\nb {}",
message: messages.expected(1),
line: 3,
column: 1
},
{
code: "a {}\r\n\r\n\r\nb {}",
+ fixed: "a {}\r\n\r\nb {}",
message: messages.expected(1),
line: 3,
column: 1
},
{
code: "a {}\n\n/** horse */\n\n\nb {}",
+ fixed: "a {}\n\n/** horse */\n\nb {}",
message: messages.expected(1),
line: 5,
column: 1
},
{
code: "a {}\r\n\r\n/** horse */\r\n\r\n\r\nb {}",
+ fixed: "a {}\r\n\r\n/** horse */\r\n\r\nb {}",
message: messages.expected(1),
line: 5,
column: 1
},
{
code: "/* horse\n\n\n */\na {}",
+ fixed: "/* horse\n\n */\na {}",
message: messages.expected(1),
line: 3,
column: 1
},
{
code: "/* horse\r\n\r\n\r\n */\r\na {}",
+ fixed: "/* horse\r\n\r\n */\r\na {}",
message: messages.expected(1),
line: 3,
column: 1
@@ -189,6 +202,12 @@ a {color: pink;}
/* horse */
+
+`,
+ fixed: `
+
`,
message: messages.expected(1),
@@ -200,6 +219,10 @@ a {color: pink;}
code: `
+
`,
+ fixed: `
`,
message: messages.expected(1),
@@ -216,6 +239,16 @@ a {}
a {}
+
+`,
+ fixed: `
+
+
`,
message: messages.expected(1),
@@ -280,6 +313,14 @@ export default styled.div\`
/* horse */
+ color: #00
+\`;
+`,
+ fixed: `
+import styled from 'styled-components';
+export default styled.div\`
+ /* horse */
+
color: #00
\`;
`,
@@ -300,6 +341,18 @@ export const style2 = styled.div\`
color: #00
+\`;`,
+ fixed: `
+import styled from 'styled-components';
+// styled style1
+export const style1 = styled.div\`
+ color: #00
+
+\`;
+// styled style2
+export const style2 = styled.div\`
+ color: #00
+
\`;`,
message: messages.expected(1),
line: 12,
@@ -336,36 +389,42 @@ testRule(rule, {
reject: [
{
code: "a {}\n\n\n\nb {}",
+ fixed: "a {}\n\n\nb {}",
message: messages.expected(2),
line: 4,
column: 1
},
{
code: "a {}\r\n\r\n\r\n\r\nb {}",
+ fixed: "a {}\r\n\r\n\r\nb {}",
message: messages.expected(2),
line: 4,
column: 1
},
{
code: "a {}\n\n/** horse */\n\n\n\nb {}",
+ fixed: "a {}\n\n/** horse */\n\n\nb {}",
message: messages.expected(2),
line: 6,
column: 1
},
{
code: "a {}\r\n\r\n/** horse */\r\n\r\n\r\n\r\nb {}",
+ fixed: "a {}\r\n\r\n/** horse */\r\n\r\n\r\nb {}",
message: messages.expected(2),
line: 6,
column: 1
},
{
code: "/* horse\n\n\n\n */\na {}",
+ fixed: "/* horse\n\n\n */\na {}",
message: messages.expected(2),
line: 4,
column: 1
},
{
code: "/* horse\r\n\r\n\r\n\r\n */\r\na {}",
+ fixed: "/* horse\r\n\r\n\r\n */\r\na {}",
message: messages.expected(2),
line: 4,
column: 1
@@ -394,18 +453,21 @@ testRule(rule, {
reject: [
{
code: "\n\n\n// one",
+ fixed: "\n\n// one",
message: messages.expected(2),
line: 3,
column: 1
},
{
code: "// one\n\n\n",
+ fixed: "// one\n\n",
message: messages.expected(2),
line: 4,
column: 1
},
{
code: "// one\n\n\n\n// two\n",
+ fixed: "// one\n\n\n// two\n",
message: messages.expected(2),
line: 4,
column: 1
@@ -441,12 +503,14 @@ testRule(rule, {
reject: [
{
code: "a {}\n\n/*\n\n\n\n\n*/\n\n\n\nb {}",
+ fixed: "a {}\n\n/*\n\n\n\n\n*/\n\n\nb {}",
message: messages.expected(2),
line: 11,
column: 1
},
{
code: "a {}\r\n\r\n/**\r\n\r\n\r\n\r\n\r\n*/\r\n\r\n\r\n\r\nb {}",
+ fixed: "a {}\r\n\r\n/**\r\n\r\n\r\n\r\n\r\n*/\r\n\r\n\r\nb {}",
message: messages.expected(2),
line: 11,
column: 1
diff --git a/lib/rules/max-empty-lines/index.js b/lib/rules/max-empty-lines/index.js
index d32d07d065..92f6f5ccfd 100644
--- a/lib/rules/max-empty-lines/index.js
+++ b/lib/rules/max-empty-lines/index.js
@@ -14,7 +14,7 @@ const messages = ruleMessages(ruleName, {
`Expected no more than ${max} empty ${max === 1 ? "line" : "lines"}`
});
-const rule = function(max, options) {
+const rule = function(max, options, context) {
let emptyLines = 0;
let lastIndex = -1;
@@ -40,6 +40,59 @@ const rule = function(max, options) {
}
const ignoreComments = optionsMatches(options, "ignore", "comments");
+ const getChars = _.partial(replaceEmptyLines, max);
+
+ /**
+ * 1. walk nodes & replace enterchar
+ * 2. deal with special case.
+ */
+ if (context.fix) {
+ root.walk(node => {
+ if (node.type === "comment") {
+ // for inline comments
+ if (node.raws.inline) {
+ node.raws.before = getChars(node.raws.before);
+ }
+
+ if (!ignoreComments) {
+ node.raws.left = getChars(node.raws.left);
+ node.raws.right = getChars(node.raws.right);
+ }
+ } else {
+ if (node.raws.before) {
+ node.raws.before = getChars(node.raws.before);
+ }
+
+ if (node.raws.after) {
+ node.raws.after = getChars(node.raws.after);
+ }
+ }
+ });
+
+ // first node
+ const firstNodeRawsBefore = _.get(root, "first.raws.before");
+
+ // not document node
+ if (_.get(root, "constructor.name") !== "Document") {
+ if (firstNodeRawsBefore) {
+ _.set(root, "first.raws.before", getChars(firstNodeRawsBefore, true));
+ }
+ }
+
+ // root raws
+ const rootRawsAfter = _.get(root, "raws.after");
+
+ if (rootRawsAfter) {
+ // when max setted 0, should be treated as 1 in this situation.
+ _.set(
+ root,
+ "raws.after",
+ replaceEmptyLines(max === 0 ? 1 : max, rootRawsAfter, true)
+ );
+ }
+
+ return;
+ }
emptyLines = 0;
lastIndex = -1;
@@ -98,6 +151,39 @@ const rule = function(max, options) {
}
}
}
+
+ function replaceEmptyLines(max, str, isSpecialCase = false) {
+ const maxLength = isSpecialCase ? max : max + 1;
+
+ if (maxLength === 0) {
+ return "";
+ }
+
+ const emptyLFLines = _.repeat("\n", maxLength);
+ const emptyCRLFLines = _.repeat("\r\n", maxLength);
+
+ let result;
+
+ if (/(\r\n)+/g.test(str)) {
+ result = str.replace(/(\r\n)+/g, $1 => {
+ if ($1.length > maxLength) {
+ return emptyCRLFLines;
+ }
+
+ return $1;
+ });
+ } else {
+ result = str.replace(/(\n)+/g, $1 => {
+ if ($1.length > maxLength) {
+ return emptyLFLines;
+ }
+
+ return $1;
+ });
+ }
+
+ return result;
+ }
};
};