-
-
Notifications
You must be signed in to change notification settings - Fork 928
/
index.js
116 lines (96 loc) · 3.01 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
'use strict';
const addEmptyLineAfter = require('../../utils/addEmptyLineAfter');
const blockString = require('../../utils/blockString');
const hasBlock = require('../../utils/hasBlock');
const hasEmptyBlock = require('../../utils/hasEmptyBlock');
const hasEmptyLine = require('../../utils/hasEmptyLine');
const isSingleLineString = require('../../utils/isSingleLineString');
const optionsMatches = require('../../utils/optionsMatches');
const removeEmptyLineAfter = require('../../utils/removeEmptyLinesAfter');
const report = require('../../utils/report');
const ruleMessages = require('../../utils/ruleMessages');
const validateOptions = require('../../utils/validateOptions');
const ruleName = 'block-closing-brace-empty-line-before';
const messages = ruleMessages(ruleName, {
expected: 'Expected empty line before closing brace',
rejected: 'Unexpected empty line before closing brace',
});
const rule = function(expectation, options, context) {
return (root, result) => {
const validOptions = validateOptions(
result,
ruleName,
{
actual: expectation,
possible: ['always-multi-line', 'never'],
},
{
actual: options,
possible: {
except: ['after-closing-brace'],
},
optional: true,
},
);
if (!validOptions) {
return;
}
// Check both kinds of statements: rules and at-rules
root.walkRules(check);
root.walkAtRules(check);
function check(statement) {
// Return early if blockless or has empty block
if (!hasBlock(statement) || hasEmptyBlock(statement)) {
return;
}
// Get whitespace after ""}", ignoring extra semicolon
const before = (statement.raws.after || '').replace(/;+/, '');
// Calculate index
const statementString = statement.toString();
let index = statementString.length - 1;
if (statementString[index - 1] === '\r') {
index -= 1;
}
// Set expectation
const expectEmptyLineBefore = (() => {
const childNodeTypes = statement.nodes.map((item) => item.type);
// Reverse the primary options if `after-closing-brace` is set
if (
optionsMatches(options, 'except', 'after-closing-brace') &&
statement.type === 'atrule' &&
childNodeTypes.indexOf('decl') === -1
) {
return expectation === 'never' ? true : false;
}
return expectation === 'always-multi-line' && !isSingleLineString(blockString(statement))
? true
: false;
})();
// Check for at least one empty line
const hasEmptyLineBefore = hasEmptyLine(before);
// Return if the expectation is met
if (expectEmptyLineBefore === hasEmptyLineBefore) {
return;
}
if (context.fix) {
if (expectEmptyLineBefore) {
addEmptyLineAfter(statement, context.newline);
} else {
removeEmptyLineAfter(statement, context.newline);
}
return;
}
const message = expectEmptyLineBefore ? messages.expected : messages.rejected;
report({
message,
result,
ruleName,
node: statement,
index,
});
}
};
};
rule.ruleName = ruleName;
rule.messages = messages;
module.exports = rule;