Skip to content

Commit a0462e0

Browse files
committed
Separate code into modules
1 parent c8ea3dd commit a0462e0

13 files changed

+733
-629
lines changed

index.js

Lines changed: 7 additions & 629 deletions
Large diffs are not rendered by default.

lib/checkOption.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use strict';
2+
3+
const _ = require('lodash');
4+
5+
module.exports = function checkOption(opts, primaryOption, secondaryOption, value) {
6+
const secondaryOptionValues = _.get(opts[primaryOption][1], secondaryOption);
7+
8+
return _.includes(secondaryOptionValues, value);
9+
};
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
'use strict';
2+
3+
const checkOption = require('../checkOption');
4+
const cleanEmptyLines = require('../cleanEmptyLines');
5+
const createEmptyLines = require('../createEmptyLines');
6+
const hasEmptyLine = require('../hasEmptyLine');
7+
const isAfterCommentLine = require('../isAfterCommentLine');
8+
const isAtRuleAfterSameNameAtRule = require('../isAtRuleAfterSameNameAtRule');
9+
const isBlocklessAtRuleAfterBlocklessAtRule = require('../isBlocklessAtRuleAfterBlocklessAtRule');
10+
const isBlocklessAtRuleAfterSameNameBlocklessAtRule = require('../isBlocklessAtRuleAfterSameNameBlocklessAtRule');
11+
const isFirstNested = require('../isFirstNested');
12+
13+
module.exports = function (css, opts) {
14+
const optionName = 'at-rule-nested-empty-line-before';
15+
16+
css.walkAtRules(function (atRule) {
17+
// Only attend to nested at-rules
18+
if (atRule.parent === css) {
19+
return;
20+
}
21+
22+
// Return early if at-rule is to be ignored
23+
if (checkOption(opts, optionName, 'ignoreAtRules', atRule.name)) {
24+
return;
25+
}
26+
27+
// Optionally ignore the expectation if the node is blockless
28+
if (
29+
checkOption(opts, optionName, 'ignore', 'blockless-after-blockless')
30+
&& isBlocklessAtRuleAfterBlocklessAtRule(atRule)
31+
) {
32+
return;
33+
}
34+
35+
// Optionally ignore the expection if the node is blockless
36+
// and following another blockless at-rule with the same name
37+
if (
38+
checkOption(opts, optionName, 'ignore', 'blockless-after-same-name-blockless')
39+
&& isBlocklessAtRuleAfterSameNameBlocklessAtRule(atRule)
40+
) {
41+
return;
42+
}
43+
44+
// Optionally ignore the expectation if a comment precedes this node
45+
if (
46+
checkOption(opts, optionName, 'ignore', 'after-comment')
47+
&& isAfterCommentLine(atRule)
48+
) {
49+
return;
50+
}
51+
52+
let expectEmptyLineBefore = opts['at-rule-nested-empty-line-before'][0];
53+
54+
// Optionally reverse the expectation if any exceptions apply
55+
if (
56+
checkOption(opts, optionName, 'except', 'first-nested')
57+
&& isFirstNested(atRule)
58+
) {
59+
expectEmptyLineBefore = !expectEmptyLineBefore;
60+
}
61+
62+
if (
63+
checkOption(opts, optionName, 'except', 'blockless-after-blockless')
64+
&& isBlocklessAtRuleAfterBlocklessAtRule(atRule)
65+
) {
66+
expectEmptyLineBefore = !expectEmptyLineBefore;
67+
}
68+
69+
if (
70+
checkOption(opts, optionName, 'except', 'blockless-after-same-name-blockless')
71+
&& isBlocklessAtRuleAfterSameNameBlocklessAtRule(atRule)
72+
) {
73+
expectEmptyLineBefore = !expectEmptyLineBefore;
74+
}
75+
76+
if (
77+
checkOption(opts, optionName, 'except', 'after-same-name')
78+
&& isAtRuleAfterSameNameAtRule(atRule)
79+
) {
80+
expectEmptyLineBefore = !expectEmptyLineBefore;
81+
}
82+
83+
const hasEmptyLineBefore = hasEmptyLine(atRule.raws.before);
84+
85+
// Return if the expectation is met
86+
if (expectEmptyLineBefore === hasEmptyLineBefore) {
87+
return;
88+
}
89+
90+
if (expectEmptyLineBefore) {
91+
if (atRule.raws.before.indexOf('\n') === -1) {
92+
atRule.raws.before = `\n${atRule.raws.before}`;
93+
}
94+
95+
atRule.raws.before = createEmptyLines(1) + atRule.raws.before;
96+
} else {
97+
atRule.raws.before = cleanEmptyLines(atRule.raws.before);
98+
}
99+
});
100+
};

lib/features/clean-empty-lines.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
3+
const cleanEmptyLines = require('../cleanEmptyLines');
4+
const isRuleWithNodes = require('../isRuleWithNodes');
5+
6+
module.exports = function (css, opts) {
7+
if (opts['clean-empty-lines'] !== true) {
8+
return;
9+
}
10+
11+
css.walk(function (node) {
12+
if (isRuleWithNodes(node)) {
13+
// Remove empty lines before every node
14+
node.each(function (childNode) {
15+
if (childNode.raws.before) {
16+
childNode.raws.before = cleanEmptyLines(childNode.raws.before);
17+
}
18+
});
19+
20+
// Remove empty lines after the last node
21+
if (node.raws.after) {
22+
node.raws.after = cleanEmptyLines(node.raws.after);
23+
}
24+
}
25+
});
26+
};
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
'use strict';
2+
3+
const checkOption = require('../checkOption');
4+
const cleanEmptyLines = require('../cleanEmptyLines');
5+
const createEmptyLines = require('../createEmptyLines');
6+
const hasEmptyLine = require('../hasEmptyLine');
7+
const isAfterCommentLine = require('../isAfterCommentLine');
8+
const isRuleWithNodes = require('../isRuleWithNodes');
9+
10+
module.exports = function (css, opts) {
11+
const optionName = 'comment-empty-line-before';
12+
13+
css.walk(function (node) {
14+
// Process only rules and atrules with nodes
15+
if (isRuleWithNodes(node)) {
16+
node.walkComments((comment) => {
17+
// Optionally ignore stylelint commands
18+
if (
19+
checkOption(opts, optionName, 'ignore', 'stylelint-command')
20+
&& comment.text.indexOf('stylelint-') === 0
21+
) {
22+
return;
23+
}
24+
25+
if (
26+
checkOption(opts, optionName, 'ignore', 'after-comment')
27+
&& isAfterCommentLine(comment)
28+
) {
29+
return;
30+
}
31+
32+
// Ignore inline comments in custom syntaxes
33+
if (
34+
comment.raws.inline
35+
|| comment.inline
36+
) {
37+
return;
38+
}
39+
40+
const before = comment.raws.before || '';
41+
42+
// Ignore shared-line comments
43+
if (before.indexOf('\n') === -1) {
44+
return;
45+
}
46+
47+
const hasEmptyLineBefore = hasEmptyLine(before);
48+
49+
let expectEmptyLineBefore = opts['comment-empty-line-before'][0];
50+
51+
// Optionally reverse the expectation if any exceptions apply
52+
if (
53+
checkOption(opts, optionName, 'except', 'first-nested')
54+
&& comment === comment.parent.first
55+
) {
56+
expectEmptyLineBefore = !expectEmptyLineBefore;
57+
}
58+
59+
// Return if the expectation is met
60+
if (expectEmptyLineBefore === hasEmptyLineBefore) {
61+
return;
62+
}
63+
64+
if (expectEmptyLineBefore) {
65+
comment.raws.before = createEmptyLines(1) + comment.raws.before;
66+
} else {
67+
comment.raws.before = cleanEmptyLines(comment.raws.before);
68+
}
69+
});
70+
}
71+
});
72+
};
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
'use strict';
2+
3+
const isStandardSyntaxDeclaration = require('../isStandardSyntaxDeclaration');
4+
const isCustomProperty = require('../isCustomProperty');
5+
const isAfterCommentLine = require('../isAfterCommentLine');
6+
const isSingleLineBlock = require('../isSingleLineBlock');
7+
const isFirstNested = require('../isFirstNested');
8+
const cleanEmptyLines = require('../cleanEmptyLines');
9+
const createEmptyLines = require('../createEmptyLines');
10+
const getPreviousNonSharedLineCommentNode = require('../getPreviousNonSharedLineCommentNode');
11+
const hasEmptyLine = require('../hasEmptyLine');
12+
const checkOption = require('../checkOption');
13+
14+
module.exports = function (css, opts) {
15+
const optionName = 'custom-property-empty-line-before';
16+
17+
css.walkDecls(function (decl) {
18+
const prop = decl.prop;
19+
const parent = decl.parent;
20+
21+
if (!isStandardSyntaxDeclaration(decl) || !isCustomProperty(prop)) {
22+
return;
23+
}
24+
25+
// Optionally ignore the node if a comment precedes it
26+
if (
27+
checkOption(opts, optionName, 'ignore', 'after-comment')
28+
&& isAfterCommentLine(decl)
29+
) {
30+
return;
31+
}
32+
33+
// Optionally ignore nodes inside single-line blocks
34+
if (
35+
checkOption(opts, optionName, 'ignore', 'inside-single-line-block')
36+
&& isSingleLineBlock(parent)
37+
) {
38+
return;
39+
}
40+
41+
let expectEmptyLineBefore = opts['custom-property-empty-line-before'][0];
42+
43+
// Optionally reverse the expectation for the first nested node
44+
if (
45+
checkOption(opts, optionName, 'except', 'first-nested')
46+
&& isFirstNested(decl)
47+
) {
48+
expectEmptyLineBefore = !expectEmptyLineBefore;
49+
}
50+
51+
// Optionally reverse the expectation if a comment precedes this node
52+
if (
53+
checkOption(opts, optionName, 'except', 'after-comment')
54+
&& isAfterCommentLine(decl)
55+
) {
56+
expectEmptyLineBefore = !expectEmptyLineBefore;
57+
}
58+
59+
// Optionally reverse the expectation if a custom property precedes this node
60+
const prevNode = getPreviousNonSharedLineCommentNode(decl);
61+
62+
if (
63+
checkOption(opts, optionName, 'except', 'after-custom-property')
64+
&& prevNode
65+
&& prevNode.prop
66+
&& isCustomProperty(prevNode.prop)
67+
) {
68+
expectEmptyLineBefore = !expectEmptyLineBefore;
69+
}
70+
71+
const hasEmptyLineBefore = hasEmptyLine(decl.raws.before);
72+
73+
// Return if the expectation is met
74+
if (expectEmptyLineBefore === hasEmptyLineBefore) {
75+
return;
76+
}
77+
78+
if (expectEmptyLineBefore) {
79+
if (decl.raws.before.indexOf('\n') === -1) {
80+
decl.raws.before = `\n${decl.raws.before}`;
81+
}
82+
83+
decl.raws.before = createEmptyLines(1) + decl.raws.before;
84+
} else {
85+
decl.raws.before = cleanEmptyLines(decl.raws.before);
86+
}
87+
});
88+
};
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
'use strict';
2+
3+
const isStandardSyntaxDeclaration = require('../isStandardSyntaxDeclaration');
4+
const isCustomProperty = require('../isCustomProperty');
5+
const isAfterCommentLine = require('../isAfterCommentLine');
6+
const isAfterStandardPropertyDeclaration = require('../isAfterStandardPropertyDeclaration');
7+
const isSingleLineBlock = require('../isSingleLineBlock');
8+
const isFirstNested = require('../isFirstNested');
9+
const cleanEmptyLines = require('../cleanEmptyLines');
10+
const createEmptyLines = require('../createEmptyLines');
11+
const hasEmptyLine = require('../hasEmptyLine');
12+
const checkOption = require('../checkOption');
13+
14+
module.exports = function (css, opts) {
15+
const optionName = 'declaration-empty-line-before';
16+
17+
css.walkDecls(function (decl) {
18+
const prop = decl.prop;
19+
const parent = decl.parent;
20+
21+
if (!isStandardSyntaxDeclaration(decl)) {
22+
return;
23+
}
24+
25+
if (isCustomProperty(prop)) {
26+
return;
27+
}
28+
29+
// Optionally ignore the node if a comment precedes it
30+
if (
31+
checkOption(opts, optionName, 'ignore', 'after-comment')
32+
&& isAfterCommentLine(decl)
33+
) {
34+
return;
35+
}
36+
37+
// Optionally ignore the node if a declaration precedes it
38+
if (
39+
checkOption(opts, optionName, 'ignore', 'after-declaration')
40+
&& isAfterStandardPropertyDeclaration(decl)
41+
) {
42+
return;
43+
}
44+
45+
// Optionally ignore nodes inside single-line blocks
46+
if (
47+
checkOption(opts, optionName, 'ignore', 'inside-single-line-block')
48+
&& isSingleLineBlock(parent)
49+
) {
50+
return;
51+
}
52+
53+
let expectEmptyLineBefore = opts['declaration-empty-line-before'][0];
54+
55+
// Optionally reverse the expectation for the first nested node
56+
if (
57+
checkOption(opts, optionName, 'except', 'first-nested')
58+
&& isFirstNested(decl)
59+
) {
60+
expectEmptyLineBefore = !expectEmptyLineBefore;
61+
}
62+
63+
// Optionally reverse the expectation if a comment precedes this node
64+
if (
65+
checkOption(opts, optionName, 'except', 'after-comment')
66+
&& isAfterCommentLine(decl)
67+
) {
68+
expectEmptyLineBefore = !expectEmptyLineBefore;
69+
}
70+
71+
// Optionally reverse the expectation if a declaration precedes this node
72+
if (
73+
checkOption(opts, optionName, 'except', 'after-declaration')
74+
&& isAfterStandardPropertyDeclaration(decl)
75+
) {
76+
expectEmptyLineBefore = !expectEmptyLineBefore;
77+
}
78+
79+
const hasEmptyLineBefore = hasEmptyLine(decl.raws.before);
80+
81+
// Return if the expectation is met
82+
if (expectEmptyLineBefore === hasEmptyLineBefore) {
83+
return;
84+
}
85+
86+
if (expectEmptyLineBefore) {
87+
if (decl.raws.before.indexOf('\n') === -1) {
88+
decl.raws.before = `\n${decl.raws.before}`;
89+
}
90+
91+
decl.raws.before = createEmptyLines(1) + decl.raws.before;
92+
} else {
93+
decl.raws.before = cleanEmptyLines(decl.raws.before);
94+
}
95+
});
96+
};

0 commit comments

Comments
 (0)