UNPKG

3.15 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const _ = require('lodash');
6const beforeBlockString = require('../../utils/beforeBlockString');
7const blockString = require('../../utils/blockString');
8const hasBlock = require('../../utils/hasBlock');
9const hasEmptyBlock = require('../../utils/hasEmptyBlock');
10const optionsMatches = require('../../utils/optionsMatches');
11const report = require('../../utils/report');
12const ruleMessages = require('../../utils/ruleMessages');
13const validateOptions = require('../../utils/validateOptions');
14const whitespaceChecker = require('../../utils/whitespaceChecker');
15
16const ruleName = 'block-opening-brace-space-before';
17
18const messages = ruleMessages(ruleName, {
19 expectedBefore: () => 'Expected single space before "{"',
20 rejectedBefore: () => 'Unexpected whitespace before "{"',
21 expectedBeforeSingleLine: () => 'Expected single space before "{" of a single-line block',
22 rejectedBeforeSingleLine: () => 'Unexpected whitespace before "{" of a single-line block',
23 expectedBeforeMultiLine: () => 'Expected single space before "{" of a multi-line block',
24 rejectedBeforeMultiLine: () => 'Unexpected whitespace before "{" of a multi-line block',
25});
26
27function rule(expectation, options, context) {
28 const checker = whitespaceChecker('space', expectation, messages);
29
30 return (root, result) => {
31 const validOptions = validateOptions(
32 result,
33 ruleName,
34 {
35 actual: expectation,
36 possible: [
37 'always',
38 'never',
39 'always-single-line',
40 'never-single-line',
41 'always-multi-line',
42 'never-multi-line',
43 ],
44 },
45 {
46 actual: options,
47 possible: {
48 ignoreAtRules: [_.isString, _.isRegExp],
49 ignoreSelectors: [_.isString, _.isRegExp],
50 },
51 optional: true,
52 },
53 );
54
55 if (!validOptions) {
56 return;
57 }
58
59 // Check both kinds of statements: rules and at-rules
60 root.walkRules(check);
61 root.walkAtRules(check);
62
63 function check(statement) {
64 // Return early if blockless or has an empty block
65 if (!hasBlock(statement) || hasEmptyBlock(statement)) {
66 return;
67 }
68
69 // Return early if at-rule is to be ignored
70 if (optionsMatches(options, 'ignoreAtRules', statement.name)) {
71 return;
72 }
73
74 // Return early if selector is to be ignored
75 if (optionsMatches(options, 'ignoreSelectors', statement.selector)) {
76 return;
77 }
78
79 const source = beforeBlockString(statement);
80 const beforeBraceNoRaw = beforeBlockString(statement, {
81 noRawBefore: true,
82 });
83
84 let index = beforeBraceNoRaw.length - 1;
85
86 if (beforeBraceNoRaw[index - 1] === '\r') {
87 index -= 1;
88 }
89
90 checker.before({
91 source,
92 index: source.length,
93 lineCheckStr: blockString(statement),
94 err: (m) => {
95 if (context.fix) {
96 if (expectation.startsWith('always')) {
97 statement.raws.between = ' ';
98
99 return;
100 }
101
102 if (expectation.startsWith('never')) {
103 statement.raws.between = '';
104
105 return;
106 }
107 }
108
109 report({
110 message: m,
111 node: statement,
112 index,
113 result,
114 ruleName,
115 });
116 },
117 });
118 }
119 };
120}
121
122rule.ruleName = ruleName;
123rule.messages = messages;
124module.exports = rule;