102 lines
2.3 KiB
JavaScript
102 lines
2.3 KiB
JavaScript
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var visit = require('rework-visit');
|
|
|
|
/**
|
|
* Define custom function.
|
|
*/
|
|
|
|
module.exports = function(functions, args) {
|
|
if (!functions) throw new Error('functions object required');
|
|
return function(style){
|
|
var functionMatcher = functionMatcherBuilder(Object.keys(functions).join('|'));
|
|
|
|
visit(style, function(declarations){
|
|
func(declarations, functions, functionMatcher, args);
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Visit declarations and apply functions.
|
|
*
|
|
* @param {Array} declarations
|
|
* @param {Object} functions
|
|
* @param {RegExp} functionMatcher
|
|
* @param {Boolean} [parseArgs]
|
|
* @api private
|
|
*/
|
|
|
|
function func(declarations, functions, functionMatcher, parseArgs) {
|
|
if (!declarations) return;
|
|
if (false !== parseArgs) parseArgs = true;
|
|
|
|
declarations.forEach(function(decl){
|
|
if ('comment' == decl.type) return;
|
|
var generatedFuncs = [], result, generatedFunc;
|
|
|
|
while (decl.value.match(functionMatcher)) {
|
|
decl.value = decl.value.replace(functionMatcher, function(_, name, args){
|
|
if (parseArgs) {
|
|
args = args.split(/\s*,\s*/).map(strip);
|
|
} else {
|
|
args = [strip(args)];
|
|
}
|
|
// Ensure result is string
|
|
result = '' + functions[name].apply(decl, args);
|
|
|
|
// Prevent fall into infinite loop like this:
|
|
//
|
|
// {
|
|
// url: function(path) {
|
|
// return 'url(' + '/some/prefix' + path + ')'
|
|
// }
|
|
// }
|
|
//
|
|
generatedFunc = {from: name, to: name + getRandomString()};
|
|
result = result.replace(functionMatcherBuilder(name), generatedFunc.to + '($2)');
|
|
generatedFuncs.push(generatedFunc);
|
|
return result;
|
|
});
|
|
}
|
|
|
|
generatedFuncs.forEach(function(func) {
|
|
decl.value = decl.value.replace(func.to, func.from);
|
|
})
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Build function regexp
|
|
*
|
|
* @param {String} name
|
|
* @api private
|
|
*/
|
|
|
|
function functionMatcherBuilder(name) {
|
|
// /(?!\W+)(\w+)\(([^()]+)\)/
|
|
return new RegExp("(?!\\W+)(" + name + ")\\(([^\(\)]+)\\)");
|
|
}
|
|
|
|
/**
|
|
* get random string
|
|
*
|
|
* @api private
|
|
*/
|
|
|
|
function getRandomString() {
|
|
return Math.random().toString(36).slice(2);
|
|
}
|
|
|
|
/**
|
|
* strip quotes from string
|
|
* @api private
|
|
*/
|
|
|
|
function strip(str) {
|
|
if ('"' == str[0] || "'" == str[0]) return str.slice(1, -1);
|
|
return str;
|
|
}
|