UNPKG

3.14 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
6const report = require('../../utils/report');
7const ruleMessages = require('../../utils/ruleMessages');
8const styleSearch = require('style-search');
9const validateOptions = require('../../utils/validateOptions');
10const whitespaceChecker = require('../../utils/whitespaceChecker');
11
12const ruleName = 'selector-list-comma-newline-after';
13
14const messages = ruleMessages(ruleName, {
15 expectedAfter: () => 'Expected newline after ","',
16 expectedAfterMultiLine: () => 'Expected newline after "," in a multi-line list',
17 rejectedAfterMultiLine: () => 'Unexpected whitespace after "," in a multi-line list',
18});
19
20function rule(expectation, options, context) {
21 const checker = whitespaceChecker('newline', expectation, messages);
22
23 return (root, result) => {
24 const validOptions = validateOptions(result, ruleName, {
25 actual: expectation,
26 possible: ['always', 'always-multi-line', 'never-multi-line'],
27 });
28
29 if (!validOptions) {
30 return;
31 }
32
33 // TODO: Issue #4985
34 // eslint-disable-next-line no-shadow
35 root.walkRules((rule) => {
36 if (!isStandardSyntaxRule(rule)) {
37 return;
38 }
39
40 // Get raw selector so we can allow end-of-line comments, e.g.
41 // a, /* comment */
42 // b {}
43 const selector = rule.raws.selector ? rule.raws.selector.raw : rule.selector;
44
45 const fixIndices = [];
46
47 styleSearch(
48 {
49 source: selector,
50 target: ',',
51 functionArguments: 'skip',
52 },
53 (match) => {
54 const nextChars = selector.substr(match.endIndex, selector.length - match.endIndex);
55
56 // If there's a // comment, that means there has to be a newline
57 // ending the comment so we're fine
58 if (/^\s+\/\//.test(nextChars)) {
59 return;
60 }
61
62 // If there are spaces and then a comment begins, look for the newline
63 const indextoCheckAfter = /^\s+\/\*/.test(nextChars)
64 ? selector.indexOf('*/', match.endIndex) + 1
65 : match.startIndex;
66
67 checker.afterOneOnly({
68 source: selector,
69 index: indextoCheckAfter,
70 err: (m) => {
71 if (context.fix) {
72 fixIndices.push(indextoCheckAfter + 1);
73
74 return;
75 }
76
77 report({
78 message: m,
79 node: rule,
80 index: match.startIndex,
81 result,
82 ruleName,
83 });
84 },
85 });
86 },
87 );
88
89 if (fixIndices.length) {
90 let fixedSelector = selector;
91
92 fixIndices
93 .sort((a, b) => b - a)
94 .forEach((index) => {
95 const beforeSelector = fixedSelector.slice(0, index);
96 let afterSelector = fixedSelector.slice(index);
97
98 if (expectation.startsWith('always')) {
99 afterSelector = context.newline + afterSelector;
100 } else if (expectation.startsWith('never-multi-line')) {
101 afterSelector = afterSelector.replace(/^\s*/, '');
102 }
103
104 fixedSelector = beforeSelector + afterSelector;
105 });
106
107 if (rule.raws.selector) {
108 rule.raws.selector.raw = fixedSelector;
109 } else {
110 rule.selector = fixedSelector;
111 }
112 }
113 });
114 };
115}
116
117rule.ruleName = ruleName;
118rule.messages = messages;
119module.exports = rule;