UNPKG

3.08 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 root.walkRules((rule) => {
34 if (!isStandardSyntaxRule(rule)) {
35 return;
36 }
37
38 // Get raw selector so we can allow end-of-line comments, e.g.
39 // a, /* comment */
40 // b {}
41 const selector = rule.raws.selector ? rule.raws.selector.raw : rule.selector;
42
43 const fixIndices = [];
44
45 styleSearch(
46 {
47 source: selector,
48 target: ',',
49 functionArguments: 'skip',
50 },
51 (match) => {
52 const nextChars = selector.substr(match.endIndex, selector.length - match.endIndex);
53
54 // If there's a // comment, that means there has to be a newline
55 // ending the comment so we're fine
56 if (/^\s+\/\//.test(nextChars)) {
57 return;
58 }
59
60 // If there are spaces and then a comment begins, look for the newline
61 const indextoCheckAfter = /^\s+\/\*/.test(nextChars)
62 ? selector.indexOf('*/', match.endIndex) + 1
63 : match.startIndex;
64
65 checker.afterOneOnly({
66 source: selector,
67 index: indextoCheckAfter,
68 err: (m) => {
69 if (context.fix) {
70 fixIndices.push(indextoCheckAfter + 1);
71
72 return;
73 }
74
75 report({
76 message: m,
77 node: rule,
78 index: match.startIndex,
79 result,
80 ruleName,
81 });
82 },
83 });
84 },
85 );
86
87 if (fixIndices.length) {
88 let fixedSelector = selector;
89
90 fixIndices
91 .sort((a, b) => b - a)
92 .forEach((index) => {
93 const beforeSelector = fixedSelector.slice(0, index);
94 let afterSelector = fixedSelector.slice(index);
95
96 if (expectation.startsWith('always')) {
97 afterSelector = context.newline + afterSelector;
98 } else if (expectation.startsWith('never-multi-line')) {
99 afterSelector = afterSelector.replace(/^\s*/, '');
100 }
101
102 fixedSelector = beforeSelector + afterSelector;
103 });
104
105 if (rule.raws.selector) {
106 rule.raws.selector.raw = fixedSelector;
107 } else {
108 rule.selector = fixedSelector;
109 }
110 }
111 });
112 };
113}
114
115rule.ruleName = ruleName;
116rule.messages = messages;
117module.exports = rule;