motion
Version:
motion - moving development forward
128 lines (122 loc) • 4.5 kB
JavaScript
;
var postcss = require('postcss');
var valueParser = require('postcss-value-parser');
var walk = valueParser.walk;
var unit = valueParser.unit;
var encode = require('./lib/encode');
function isNum (node) {
return unit(node.value);
}
function transformAtRule (css, atRuleRegex, propRegex) {
var cache = {};
var ruleCache = [];
var declCache = [];
// Encode at rule names and cache the result
css.walk(function (node) {
if (node.type === 'atrule' && atRuleRegex.test(node.name)) {
if (!cache[node.params]) {
cache[node.params] = {
ident: encode(Object.keys(cache).length),
count: 0
};
}
node.params = cache[node.params].ident;
ruleCache.push(node);
} else if (node.type === 'decl' && propRegex.test(node.prop)) {
declCache.push(node);
}
});
// Iterate each property and change their names
declCache.forEach(function (decl) {
decl.value = valueParser(decl.value).walk(function (node) {
if (node.type === 'word' && node.value in cache) {
cache[node.value].count++;
node.value = cache[node.value].ident;
} else if (node.type === 'space') {
node.value = ' ';
} else if (node.type === 'div') {
node.before = node.after = '';
}
}).toString();
});
// Ensure that at rules with no references to them are left unchanged
ruleCache.forEach(function (rule) {
Object.keys(cache).forEach(function (key) {
var k = cache[key];
if (k.ident === rule.params && !k.count) {
rule.params = key;
}
});
});
}
function transformDecl (css, propOneRegex, propTwoRegex) {
var cache = {};
var declOneCache = [];
var declTwoCache = [];
css.walkDecls(function (decl) {
if (propOneRegex.test(decl.prop)) {
decl.value = valueParser(decl.value).walk(function (node) {
if (node.type === 'word' && !isNum(node)) {
if (!cache[node.value]) {
cache[node.value] = {
ident: encode(Object.keys(cache).length),
count: 0
};
}
node.value = cache[node.value].ident;
} else if (node.type === 'space') {
node.value = ' ';
}
});
declOneCache.push(decl);
} else if (propTwoRegex.test(decl.prop)) {
declTwoCache.push(decl);
}
});
declTwoCache.forEach(function (decl) {
decl.value = valueParser(decl.value).walk(function (node) {
if (node.type === 'function') {
if (node.value === 'counter' || node.value === 'counters') {
walk(node.nodes, function (node) {
if (node.type === 'word' && node.value in cache) {
cache[node.value].count++;
node.value = cache[node.value].ident;
} else if (node.type === 'div') {
node.before = node.after = '';
}
});
}
return false;
}
if (node.type === 'space') {
node.value = ' ';
}
}).toString();
});
declOneCache.forEach(function (decl) {
decl.value = decl.value.walk(function (node) {
if (node.type === 'word' && !isNum(node)) {
Object.keys(cache).forEach(function (key) {
var k = cache[key];
if (k.ident === node.value && !k.count) {
node.value = key;
}
});
}
}).toString();
});
}
module.exports = postcss.plugin('postcss-reduce-idents', function (opts) {
opts = opts || {};
return function (css) {
if (opts.counter !== false) {
transformDecl(css, /counter-(reset|increment)/, /content/);
}
if (opts.keyframes !== false) {
transformAtRule(css, /keyframes/, /animation/);
}
if (opts.counterStyle !== false) {
transformAtRule(css, /counter-style/, /(list-style|system)/);
}
};
});