UNPKG

2.86 kBJavaScriptView Raw
1'use strict';
2
3const beforeBlockString = require('../../utils/beforeBlockString');
4const blockString = require('../../utils/blockString');
5const hasBlock = require('../../utils/hasBlock');
6const hasEmptyBlock = require('../../utils/hasEmptyBlock');
7const report = require('../../utils/report');
8const ruleMessages = require('../../utils/ruleMessages');
9const validateOptions = require('../../utils/validateOptions');
10const whitespaceChecker = require('../../utils/whitespaceChecker');
11
12const ruleName = 'block-opening-brace-newline-before';
13
14const messages = ruleMessages(ruleName, {
15 expectedBefore: () => 'Expected newline before "{"',
16 expectedBeforeSingleLine: () => 'Expected newline before "{" of a single-line block',
17 rejectedBeforeSingleLine: () => 'Unexpected whitespace before "{" of a single-line block',
18 expectedBeforeMultiLine: () => 'Expected newline before "{" of a multi-line block',
19 rejectedBeforeMultiLine: () => 'Unexpected whitespace before "{" of a multi-line block',
20});
21
22function rule(expectation, options, context) {
23 const checker = whitespaceChecker('newline', expectation, messages);
24
25 return (root, result) => {
26 const validOptions = validateOptions(result, ruleName, {
27 actual: expectation,
28 possible: [
29 'always',
30 'always-single-line',
31 'never-single-line',
32 'always-multi-line',
33 'never-multi-line',
34 ],
35 });
36
37 if (!validOptions) {
38 return;
39 }
40
41 // Check both kinds of statement: rules and at-rules
42 root.walkRules(check);
43 root.walkAtRules(check);
44
45 function check(statement) {
46 // Return early if blockless or has an empty block
47 if (!hasBlock(statement) || hasEmptyBlock(statement)) {
48 return;
49 }
50
51 const source = beforeBlockString(statement);
52 const beforeBraceNoRaw = beforeBlockString(statement, {
53 noRawBefore: true,
54 });
55
56 let index = beforeBraceNoRaw.length - 1;
57
58 if (beforeBraceNoRaw[index - 1] === '\r') {
59 index -= 1;
60 }
61
62 checker.beforeAllowingIndentation({
63 lineCheckStr: blockString(statement),
64 source,
65 index: source.length,
66 err: (m) => {
67 if (context.fix) {
68 if (expectation.startsWith('always')) {
69 const spaceIndex = statement.raws.between.search(/\s+$/);
70
71 if (spaceIndex >= 0) {
72 statement.raws.between =
73 statement.raws.between.slice(0, spaceIndex) +
74 context.newline +
75 statement.raws.between.slice(spaceIndex);
76 } else {
77 statement.raws.between += context.newline;
78 }
79
80 return;
81 }
82
83 if (expectation.startsWith('never')) {
84 statement.raws.between = statement.raws.between.replace(/\s*$/, '');
85
86 return;
87 }
88 }
89
90 report({
91 message: m,
92 node: statement,
93 index,
94 result,
95 ruleName,
96 });
97 },
98 });
99 }
100 };
101}
102
103rule.ruleName = ruleName;
104rule.messages = messages;
105module.exports = rule;