UNPKG

4.64 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const _ = require('lodash');
6const declarationValueIndex = require('../../utils/declarationValueIndex');
7const isSingleLineString = require('../../utils/isSingleLineString');
8const isStandardSyntaxFunction = require('../../utils/isStandardSyntaxFunction');
9const report = require('../../utils/report');
10const ruleMessages = require('../../utils/ruleMessages');
11const validateOptions = require('../../utils/validateOptions');
12const valueParser = require('postcss-value-parser');
13
14const ruleName = 'function-parentheses-space-inside';
15
16const messages = ruleMessages(ruleName, {
17 expectedOpening: 'Expected single space after "("',
18 rejectedOpening: 'Unexpected whitespace after "("',
19 expectedClosing: 'Expected single space before ")"',
20 rejectedClosing: 'Unexpected whitespace before ")"',
21 expectedOpeningSingleLine: 'Expected single space after "(" in a single-line function',
22 rejectedOpeningSingleLine: 'Unexpected whitespace after "(" in a single-line function',
23 expectedClosingSingleLine: 'Expected single space before ")" in a single-line function',
24 rejectedClosingSingleLine: 'Unexpected whitespace before ")" in a single-line function',
25});
26
27function rule(expectation, options, context) {
28 return (root, result) => {
29 const validOptions = validateOptions(result, ruleName, {
30 actual: expectation,
31 possible: ['always', 'never', 'always-single-line', 'never-single-line'],
32 });
33
34 if (!validOptions) {
35 return;
36 }
37
38 root.walkDecls((decl) => {
39 if (!decl.value.includes('(')) {
40 return;
41 }
42
43 let hasFixed = false;
44 const declValue = _.get(decl, 'raws.value.raw', decl.value);
45 const parsedValue = valueParser(declValue);
46
47 parsedValue.walk((valueNode) => {
48 if (valueNode.type !== 'function') {
49 return;
50 }
51
52 if (!isStandardSyntaxFunction(valueNode)) {
53 return;
54 }
55
56 // Ignore function without parameters
57 if (!valueNode.nodes.length) {
58 return;
59 }
60
61 const functionString = valueParser.stringify(valueNode);
62 const isSingleLine = isSingleLineString(functionString);
63
64 // Check opening ...
65
66 const openingIndex = valueNode.sourceIndex + valueNode.value.length + 1;
67
68 if (expectation === 'always' && valueNode.before !== ' ') {
69 if (context.fix) {
70 hasFixed = true;
71 valueNode.before = ' ';
72 } else {
73 complain(messages.expectedOpening, openingIndex);
74 }
75 }
76
77 if (expectation === 'never' && valueNode.before !== '') {
78 if (context.fix) {
79 hasFixed = true;
80 valueNode.before = '';
81 } else {
82 complain(messages.rejectedOpening, openingIndex);
83 }
84 }
85
86 if (isSingleLine && expectation === 'always-single-line' && valueNode.before !== ' ') {
87 if (context.fix) {
88 hasFixed = true;
89 valueNode.before = ' ';
90 } else {
91 complain(messages.expectedOpeningSingleLine, openingIndex);
92 }
93 }
94
95 if (isSingleLine && expectation === 'never-single-line' && valueNode.before !== '') {
96 if (context.fix) {
97 hasFixed = true;
98 valueNode.before = '';
99 } else {
100 complain(messages.rejectedOpeningSingleLine, openingIndex);
101 }
102 }
103
104 // Check closing ...
105
106 const closingIndex = valueNode.sourceIndex + functionString.length - 2;
107
108 if (expectation === 'always' && valueNode.after !== ' ') {
109 if (context.fix) {
110 hasFixed = true;
111 valueNode.after = ' ';
112 } else {
113 complain(messages.expectedClosing, closingIndex);
114 }
115 }
116
117 if (expectation === 'never' && valueNode.after !== '') {
118 if (context.fix) {
119 hasFixed = true;
120 valueNode.after = '';
121 } else {
122 complain(messages.rejectedClosing, closingIndex);
123 }
124 }
125
126 if (isSingleLine && expectation === 'always-single-line' && valueNode.after !== ' ') {
127 if (context.fix) {
128 hasFixed = true;
129 valueNode.after = ' ';
130 } else {
131 complain(messages.expectedClosingSingleLine, closingIndex);
132 }
133 }
134
135 if (isSingleLine && expectation === 'never-single-line' && valueNode.after !== '') {
136 if (context.fix) {
137 hasFixed = true;
138 valueNode.after = '';
139 } else {
140 complain(messages.rejectedClosingSingleLine, closingIndex);
141 }
142 }
143 });
144
145 if (hasFixed) {
146 if (!decl.raws.value) {
147 decl.value = parsedValue.toString();
148 } else {
149 decl.raws.value.raw = parsedValue.toString();
150 }
151 }
152
153 function complain(message, offset) {
154 report({
155 ruleName,
156 result,
157 message,
158 node: decl,
159 index: declarationValueIndex(decl) + offset,
160 });
161 }
162 });
163 };
164}
165
166rule.ruleName = ruleName;
167rule.messages = messages;
168module.exports = rule;