1 |
|
2 | "use strict";
|
3 |
|
4 | const _ = require("lodash");
|
5 |
|
6 | const COMMAND_PREFIX = "stylelint-";
|
7 | const disableCommand = COMMAND_PREFIX + "disable";
|
8 | const enableCommand = COMMAND_PREFIX + "enable";
|
9 | const disableLineCommand = COMMAND_PREFIX + "disable-line";
|
10 | const disableNextLineCommand = COMMAND_PREFIX + "disable-next-line";
|
11 | const ALL_RULES = "all";
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | module.exports = function(
|
22 | root /*: Object*/,
|
23 | result /*: Object*/
|
24 | ) /*: postcss$result*/ {
|
25 | result.stylelint = result.stylelint || {};
|
26 |
|
27 |
|
28 |
|
29 | const disabledRanges = {
|
30 | all: []
|
31 | };
|
32 |
|
33 | result.stylelint.disabledRanges = disabledRanges;
|
34 | root.walkComments(checkComment);
|
35 |
|
36 | return result;
|
37 |
|
38 | function processDisableLineCommand(comment /*: postcss$comment*/) {
|
39 | getCommandRules(disableLineCommand, comment.text).forEach(ruleName => {
|
40 | disableLine(comment.source.start.line, ruleName, comment);
|
41 | });
|
42 | }
|
43 |
|
44 | function processDisableNextLineCommand(comment /*: postcss$comment*/) {
|
45 | getCommandRules(disableNextLineCommand, comment.text).forEach(ruleName => {
|
46 | disableLine(comment.source.start.line + 1, ruleName, comment);
|
47 | });
|
48 | }
|
49 |
|
50 | function disableLine(
|
51 | line /*: number*/,
|
52 | ruleName /*: string*/,
|
53 | comment /*: postcss$comment*/
|
54 | ) {
|
55 | if (ruleIsDisabled(ALL_RULES)) {
|
56 | throw comment.error("All rules have already been disabled", {
|
57 | plugin: "stylelint"
|
58 | });
|
59 | }
|
60 |
|
61 | if (ruleIsDisabled(ruleName)) {
|
62 | throw comment.error(`"${ruleName}" has already been disabled`, {
|
63 | plugin: "stylelint"
|
64 | });
|
65 | }
|
66 |
|
67 | if (ruleName === ALL_RULES) {
|
68 | Object.keys(disabledRanges).forEach(disabledRuleName => {
|
69 | startDisabledRange(line, disabledRuleName);
|
70 | endDisabledRange(line, disabledRuleName);
|
71 | });
|
72 | } else {
|
73 | startDisabledRange(line, ruleName);
|
74 | endDisabledRange(line, ruleName);
|
75 | }
|
76 | }
|
77 |
|
78 | function processDisableCommand(comment /*: postcss$comment*/) {
|
79 | getCommandRules(disableCommand, comment.text).forEach(ruleToDisable => {
|
80 | if (ruleToDisable === ALL_RULES) {
|
81 | if (ruleIsDisabled(ALL_RULES)) {
|
82 | throw comment.error("All rules have already been disabled", {
|
83 | plugin: "stylelint"
|
84 | });
|
85 | }
|
86 |
|
87 | Object.keys(disabledRanges).forEach(ruleName => {
|
88 | startDisabledRange(comment.source.start.line, ruleName);
|
89 | });
|
90 |
|
91 | return;
|
92 | }
|
93 |
|
94 | if (ruleIsDisabled(ruleToDisable)) {
|
95 | throw comment.error(`"${ruleToDisable}" has already been disabled`, {
|
96 | plugin: "stylelint"
|
97 | });
|
98 | }
|
99 |
|
100 | startDisabledRange(comment.source.start.line, ruleToDisable);
|
101 | });
|
102 | }
|
103 |
|
104 | function processEnableCommand(comment /*: postcss$comment*/) {
|
105 | getCommandRules(enableCommand, comment.text).forEach(ruleToEnable => {
|
106 | if (ruleToEnable === ALL_RULES) {
|
107 | if (
|
108 | _.values(disabledRanges).every(
|
109 | ranges => _.isEmpty(ranges) || !!_.last(ranges.end)
|
110 | )
|
111 | ) {
|
112 | throw comment.error("No rules have been disabled", {
|
113 | plugin: "stylelint"
|
114 | });
|
115 | }
|
116 |
|
117 | Object.keys(disabledRanges).forEach(ruleName => {
|
118 | if (!_.get(_.last(disabledRanges[ruleName]), "end")) {
|
119 | endDisabledRange(comment.source.end.line, ruleName);
|
120 | }
|
121 | });
|
122 |
|
123 | return;
|
124 | }
|
125 |
|
126 | if (
|
127 | ruleIsDisabled(ALL_RULES) &&
|
128 | disabledRanges[ruleToEnable] === undefined
|
129 | ) {
|
130 |
|
131 | if (!disabledRanges[ruleToEnable]) {
|
132 | disabledRanges[ruleToEnable] = _.cloneDeep(disabledRanges.all);
|
133 | } else {
|
134 | disabledRanges[ruleToEnable].push(
|
135 | _.clone(_.last(disabledRanges[ALL_RULES]))
|
136 | );
|
137 | }
|
138 |
|
139 | endDisabledRange(comment.source.end.line, ruleToEnable);
|
140 |
|
141 | return;
|
142 | }
|
143 |
|
144 | if (ruleIsDisabled(ruleToEnable)) {
|
145 | endDisabledRange(comment.source.end.line, ruleToEnable);
|
146 |
|
147 | return;
|
148 | }
|
149 |
|
150 | throw comment.error(`"${ruleToEnable}" has not been disabled`, {
|
151 | plugin: "stylelint"
|
152 | });
|
153 | });
|
154 | }
|
155 |
|
156 | function checkComment(comment /*: postcss$comment*/) {
|
157 | const text = comment.text;
|
158 |
|
159 |
|
160 |
|
161 | if (text.indexOf(COMMAND_PREFIX) !== 0) {
|
162 | return result;
|
163 | }
|
164 |
|
165 | if (text.indexOf(disableLineCommand) === 0) {
|
166 | processDisableLineCommand(comment);
|
167 | } else if (text.indexOf(disableNextLineCommand) === 0) {
|
168 | processDisableNextLineCommand(comment);
|
169 | } else if (text.indexOf(disableCommand) === 0) {
|
170 | processDisableCommand(comment);
|
171 | } else if (text.indexOf(enableCommand) === 0) {
|
172 | processEnableCommand(comment);
|
173 | }
|
174 | }
|
175 |
|
176 | function getCommandRules(
|
177 | command /*: string*/,
|
178 | fullText /*: string*/
|
179 | ) /*: Array<string>*/ {
|
180 | const rules = _.compact(fullText.slice(command.length).split(",")).map(r =>
|
181 | r.trim()
|
182 | );
|
183 |
|
184 | if (_.isEmpty(rules)) {
|
185 | return [ALL_RULES];
|
186 | }
|
187 |
|
188 | return rules;
|
189 | }
|
190 |
|
191 | function startDisabledRange(line /*: number*/, ruleName /*: string*/) {
|
192 | const rangeObj = { start: line };
|
193 |
|
194 | ensureRuleRanges(ruleName);
|
195 | disabledRanges[ruleName].push(rangeObj);
|
196 | }
|
197 |
|
198 | function endDisabledRange(line /*: number*/, ruleName /*: string*/) {
|
199 | const lastRangeForRule = _.last(disabledRanges[ruleName]);
|
200 |
|
201 | if (!lastRangeForRule) {
|
202 | return;
|
203 | }
|
204 |
|
205 |
|
206 | lastRangeForRule.end = line;
|
207 | }
|
208 |
|
209 | function ensureRuleRanges(ruleName /*: string*/) {
|
210 | if (!disabledRanges[ruleName]) {
|
211 | disabledRanges[ruleName] = _.cloneDeep(disabledRanges.all);
|
212 | }
|
213 | }
|
214 |
|
215 | function ruleIsDisabled(ruleName /*: string*/) /*: boolean*/ {
|
216 | if (disabledRanges[ruleName] === undefined) return false;
|
217 |
|
218 | if (_.last(disabledRanges[ruleName]) === undefined) return false;
|
219 |
|
220 | if (_.get(_.last(disabledRanges[ruleName]), "end") === undefined)
|
221 | return true;
|
222 |
|
223 | return false;
|
224 | }
|
225 | };
|