1 |
|
2 |
|
3 | 'use strict';
|
4 |
|
5 | const _ = require('lodash');
|
6 | const atRuleParamIndex = require('../../utils/atRuleParamIndex');
|
7 | const report = require('../../utils/report');
|
8 | const ruleMessages = require('../../utils/ruleMessages');
|
9 | const validateOptions = require('../../utils/validateOptions');
|
10 | const valueParser = require('postcss-value-parser');
|
11 |
|
12 | const ruleName = 'media-feature-parentheses-space-inside';
|
13 |
|
14 | const messages = ruleMessages(ruleName, {
|
15 | expectedOpening: 'Expected single space after "("',
|
16 | rejectedOpening: 'Unexpected whitespace after "("',
|
17 | expectedClosing: 'Expected single space before ")"',
|
18 | rejectedClosing: 'Unexpected whitespace before ")"',
|
19 | });
|
20 |
|
21 | function rule(expectation, options, context) {
|
22 | return (root, result) => {
|
23 | const validOptions = validateOptions(result, ruleName, {
|
24 | actual: expectation,
|
25 | possible: ['always', 'never'],
|
26 | });
|
27 |
|
28 | if (!validOptions) {
|
29 | return;
|
30 | }
|
31 |
|
32 | root.walkAtRules(/^media$/i, (atRule) => {
|
33 |
|
34 |
|
35 | const params = _.get(atRule, 'raws.params.raw', atRule.params);
|
36 | const indexBoost = atRuleParamIndex(atRule);
|
37 | const violations = [];
|
38 |
|
39 | const parsedParams = valueParser(params).walk((node) => {
|
40 | if (node.type === 'function') {
|
41 | const len = valueParser.stringify(node).length;
|
42 |
|
43 | if (expectation === 'never') {
|
44 | if (/[ \t]/.test(node.before)) {
|
45 | if (context.fix) node.before = '';
|
46 |
|
47 | violations.push({
|
48 | message: messages.rejectedOpening,
|
49 | index: node.sourceIndex + 1 + indexBoost,
|
50 | });
|
51 | }
|
52 |
|
53 | if (/[ \t]/.test(node.after)) {
|
54 | if (context.fix) node.after = '';
|
55 |
|
56 | violations.push({
|
57 | message: messages.rejectedClosing,
|
58 | index: node.sourceIndex - 2 + len + indexBoost,
|
59 | });
|
60 | }
|
61 | } else if (expectation === 'always') {
|
62 | if (node.before === '') {
|
63 | if (context.fix) node.before = ' ';
|
64 |
|
65 | violations.push({
|
66 | message: messages.expectedOpening,
|
67 | index: node.sourceIndex + 1 + indexBoost,
|
68 | });
|
69 | }
|
70 |
|
71 | if (node.after === '') {
|
72 | if (context.fix) node.after = ' ';
|
73 |
|
74 | violations.push({
|
75 | message: messages.expectedClosing,
|
76 | index: node.sourceIndex - 2 + len + indexBoost,
|
77 | });
|
78 | }
|
79 | }
|
80 | }
|
81 | });
|
82 |
|
83 | if (violations.length) {
|
84 | if (context.fix) {
|
85 | atRule.params = parsedParams.toString();
|
86 |
|
87 | return;
|
88 | }
|
89 |
|
90 | violations.forEach((err) => {
|
91 | report({
|
92 | message: err.message,
|
93 | node: atRule,
|
94 | index: err.index,
|
95 | result,
|
96 | ruleName,
|
97 | });
|
98 | });
|
99 | }
|
100 | });
|
101 | };
|
102 | }
|
103 |
|
104 | rule.ruleName = ruleName;
|
105 | rule.messages = messages;
|
106 | module.exports = rule;
|