UNPKG

3.51 kBJavaScriptView Raw
1"use strict";
2
3const _ = require("lodash");
4const declarationValueIndex = require("../utils/declarationValueIndex");
5const isStandardSyntaxFunction = require("../utils/isStandardSyntaxFunction");
6const report = require("../utils/report");
7const valueParser = require("postcss-value-parser");
8
9module.exports = function(opts) {
10 opts.root.walkDecls(decl => {
11 const declValue = _.get(decl, "raws.value.raw", decl.value);
12
13 let hasFixed;
14 const parsedValue = valueParser(declValue);
15
16 parsedValue.walk(valueNode => {
17 if (valueNode.type !== "function") {
18 return;
19 }
20
21 if (!isStandardSyntaxFunction(valueNode)) {
22 return;
23 }
24
25 // Ignore `url()` arguments, which may contain data URIs or other funky stuff
26 if (valueNode.value.toLowerCase() === "url") {
27 return;
28 }
29
30 const argumentStrings = valueNode.nodes.map(node =>
31 valueParser.stringify(node)
32 );
33
34 const functionArguments = (() => {
35 // Remove function name and parens
36 let result =
37 valueNode.before + argumentStrings.join("") + valueNode.after;
38
39 // 1. Remove comments including preceeding whitespace (when only succeeded by whitespace)
40 // 2. Remove all other comments, but leave adjacent whitespace intact
41 result = result.replace(
42 /( *\/(\*.*\*\/(?!\S)|\/.*)|(\/(\*.*\*\/|\/.*)))/,
43 ""
44 );
45
46 return result;
47 })();
48
49 /**
50 * Gets the index of the comma for checking.
51 * @param {Node} commaNode The comma node
52 * @param {number} nodeIndex The index of the comma node
53 * @returns {number} The index of the comma for checking
54 */
55 function getCommaCheckIndex(commaNode, nodeIndex) {
56 let commaBefore =
57 valueNode.before +
58 argumentStrings.slice(0, nodeIndex).join("") +
59 commaNode.before;
60
61 // 1. Remove comments including preceeding whitespace (when only succeeded by whitespace)
62 // 2. Remove all other comments, but leave adjacent whitespace intact
63 commaBefore = commaBefore.replace(
64 /( *\/(\*.*\*\/(?!\S)|\/.*)|(\/(\*.*\*\/|\/.*)))/,
65 ""
66 );
67
68 return commaBefore.length;
69 }
70
71 const commaDataList = [];
72
73 valueNode.nodes.forEach((node, nodeIndex) => {
74 if (node.type !== "div" || node.value !== ",") {
75 return;
76 }
77
78 const checkIndex = getCommaCheckIndex(node, nodeIndex);
79
80 commaDataList.push({
81 commaNode: node,
82 checkIndex,
83 nodeIndex
84 });
85 });
86
87 for (const { commaNode, checkIndex, nodeIndex } of commaDataList) {
88 opts.locationChecker({
89 source: functionArguments,
90 index: checkIndex,
91 err: message => {
92 const index =
93 declarationValueIndex(decl) +
94 commaNode.sourceIndex +
95 commaNode.before.length;
96
97 if (opts.fix && opts.fix(commaNode, nodeIndex, valueNode.nodes)) {
98 hasFixed = true;
99
100 return;
101 }
102
103 report({
104 index,
105 message,
106 node: decl,
107 result: opts.result,
108 ruleName: opts.checkedRuleName
109 });
110 }
111 });
112 }
113 });
114
115 if (hasFixed) {
116 if (!decl.raws.value) {
117 decl.value = parsedValue.toString();
118 } else {
119 decl.raws.value.raw = parsedValue.toString();
120 }
121 }
122 });
123};