UNPKG

2.81 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const _ = require('lodash');
6const report = require('../../utils/report');
7const ruleMessages = require('../../utils/ruleMessages');
8const validateOptions = require('../../utils/validateOptions');
9const valueParser = require('postcss-value-parser');
10
11const ruleName = 'function-max-empty-lines';
12
13const messages = ruleMessages(ruleName, {
14 expected: (max) => `Expected no more than ${max} empty ${max === 1 ? 'line' : 'lines'}`,
15});
16
17function placeIndexOnValueStart(decl) {
18 return decl.prop.length + decl.raws.between.length - 1;
19}
20
21function rule(max, options, context) {
22 const maxAdjacentNewlines = max + 1;
23
24 return (root, result) => {
25 const validOptions = validateOptions(result, ruleName, {
26 actual: max,
27 possible: _.isNumber,
28 });
29
30 if (!validOptions) {
31 return;
32 }
33
34 const violatedCRLFNewLinesRegex = new RegExp(`(?:\r\n){${maxAdjacentNewlines + 1},}`);
35 const violatedLFNewLinesRegex = new RegExp(`\n{${maxAdjacentNewlines + 1},}`);
36 const allowedLFNewLinesString = context.fix ? '\n'.repeat(maxAdjacentNewlines) : '';
37 const allowedCRLFNewLinesString = context.fix ? '\r\n'.repeat(maxAdjacentNewlines) : '';
38
39 root.walkDecls((decl) => {
40 if (!decl.value.includes('(')) {
41 return;
42 }
43
44 const stringValue = decl.raws.value ? decl.raws.value.raw : decl.value;
45 const splittedValue = [];
46 let sourceIndexStart = 0;
47
48 valueParser(stringValue).walk((node) => {
49 if (
50 node.type !== 'function' /* ignore non functions */ ||
51 node.value.length === 0 /* ignore sass lists */
52 ) {
53 return;
54 }
55
56 const stringifiedNode = valueParser.stringify(node);
57
58 if (
59 !violatedLFNewLinesRegex.test(stringifiedNode) &&
60 !violatedCRLFNewLinesRegex.test(stringifiedNode)
61 ) {
62 return;
63 }
64
65 if (context.fix) {
66 const newNodeString = stringifiedNode
67 .replace(new RegExp(violatedLFNewLinesRegex, 'gm'), allowedLFNewLinesString)
68 .replace(new RegExp(violatedCRLFNewLinesRegex, 'gm'), allowedCRLFNewLinesString);
69
70 splittedValue.push([
71 stringValue.slice(sourceIndexStart, node.sourceIndex),
72 newNodeString,
73 ]);
74 sourceIndexStart = node.sourceIndex + stringifiedNode.length;
75 } else {
76 report({
77 message: messages.expected(max),
78 node: decl,
79 index: placeIndexOnValueStart(decl) + node.sourceIndex,
80 result,
81 ruleName,
82 });
83 }
84 });
85
86 if (context.fix && splittedValue.length > 0) {
87 const updatedValue =
88 splittedValue.reduce((acc, curr) => acc + curr[0] + curr[1], '') +
89 stringValue.slice(sourceIndexStart);
90
91 if (decl.raws.value) {
92 decl.raws.value.raw = updatedValue;
93 } else {
94 decl.value = updatedValue;
95 }
96 }
97 });
98 };
99}
100
101rule.ruleName = ruleName;
102rule.messages = messages;
103module.exports = rule;