forked from antyakushev/postcss-for
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
84 lines (68 loc) · 2.51 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
var postcss = require('postcss');
var list = require('postcss/lib/list');
var vars = require('postcss-simple-vars');
module.exports = postcss.plugin('postcss-for', function (opts) {
opts = opts || {};
opts.nested = opts.nested || true;
var checkNumber, checkParams, processLoops, glob, unrollLoop;
checkNumber = function (rule) {
return function (param) {
if (isNaN(parseInt(param)) || !param.match(/^\d+\.?\d*$/)) {
if (param.indexOf('$') !== -1) {
return; // we allow variables
}
throw rule.error('Range parameter should be a number', { plugin: 'postcss-for' });
}
};
};
checkParams = function (rule, params) {
if (!params[0].match(/(^|[^\w])\@([\w\d-_]+)/) ||
params[1] !== 'from' ||
params[3] !== 'to' ||
params[5] !== 'by' ^ params[5] === undefined ) {
throw rule.error('Wrong loop syntax', { plugin: 'postcss-for' });
}
[params[2], params[4], params[6] || '0'].forEach(checkNumber(rule));
};
glob = function(iterator, value, nodes) {
var reg = new RegExp('@' + iterator, 'g');
nodes.forEach(function (node) {
for (var prop in node) {
if (typeof node[prop] === 'string') {
node[prop] = node[prop].replace(reg, value);
} else if (prop === 'nodes') {
glob(iterator, value, node.nodes);
}
}
});
};
unrollLoop = function (rule) {
var params = list.space(rule.params);
checkParams(rule, params);
var iterator = params[0].slice(1),
index = +params[2],
top = +params[4],
dir = top < index ? -1 : 1,
by = (params[6] || 1) * dir;
var value = {};
for ( var i = index; i * dir <= top * dir; i = i + by ) {
var content = rule.clone();
if (opts.nested) processLoops(content);
value[iterator] = i;
vars({ only: value })(content);
glob(iterator, i, content.nodes);
rule.parent.insertBefore(rule, content.nodes);
}
if ( rule.parent ) rule.remove();
};
processLoops = function (css) {
css.walkAtRules(function (rule) {
if ( rule.name === 'for' ) {
unrollLoop(rule);
}
});
};
return function (css) {
processLoops(css);
};
});