UNPKG

2.52 kBJavaScriptView Raw
1'use strict';
2
3const ruleMessages = require('../../utils/ruleMessages');
4const selectorListCommaWhitespaceChecker = require('../selectorListCommaWhitespaceChecker');
5const validateOptions = require('../../utils/validateOptions');
6const whitespaceChecker = require('../../utils/whitespaceChecker');
7
8const ruleName = 'selector-list-comma-space-before';
9
10const messages = ruleMessages(ruleName, {
11 expectedBefore: () => 'Expected single space before ","',
12 rejectedBefore: () => 'Unexpected whitespace before ","',
13 expectedBeforeSingleLine: () => 'Expected single space before "," in a single-line list',
14 rejectedBeforeSingleLine: () => 'Unexpected whitespace before "," in a single-line list',
15});
16
17const meta = {
18 url: 'https://stylelint.io/user-guide/rules/list/selector-list-comma-space-before',
19};
20
21/** @type {import('stylelint').Rule} */
22const rule = (primary, _secondaryOptions, context) => {
23 const checker = whitespaceChecker('space', primary, messages);
24
25 return (root, result) => {
26 const validOptions = validateOptions(result, ruleName, {
27 actual: primary,
28 possible: ['always', 'never', 'always-single-line', 'never-single-line'],
29 });
30
31 if (!validOptions) {
32 return;
33 }
34
35 /** @type {Map<import('postcss').Rule, number[]> | undefined} */
36 let fixData;
37
38 selectorListCommaWhitespaceChecker({
39 root,
40 result,
41 locationChecker: checker.before,
42 checkedRuleName: ruleName,
43 fix: context.fix
44 ? (ruleNode, index) => {
45 fixData = fixData || new Map();
46 const commaIndices = fixData.get(ruleNode) || [];
47
48 commaIndices.push(index);
49 fixData.set(ruleNode, commaIndices);
50
51 return true;
52 }
53 : null,
54 });
55
56 if (fixData) {
57 for (const [ruleNode, commaIndices] of fixData.entries()) {
58 let selector = ruleNode.raws.selector ? ruleNode.raws.selector.raw : ruleNode.selector;
59
60 for (const index of commaIndices.sort((a, b) => b - a)) {
61 let beforeSelector = selector.slice(0, index);
62 const afterSelector = selector.slice(index);
63
64 if (primary.includes('always')) {
65 beforeSelector = beforeSelector.replace(/\s*$/, ' ');
66 } else if (primary.includes('never')) {
67 beforeSelector = beforeSelector.replace(/\s*$/, '');
68 }
69
70 selector = beforeSelector + afterSelector;
71 }
72
73 if (ruleNode.raws.selector) {
74 ruleNode.raws.selector.raw = selector;
75 } else {
76 ruleNode.selector = selector;
77 }
78 }
79 }
80 };
81};
82
83rule.ruleName = ruleName;
84rule.messages = messages;
85rule.meta = meta;
86module.exports = rule;