diff --git a/index.js b/index.js index f6c9289..e74fcc3 100644 --- a/index.js +++ b/index.js @@ -36,7 +36,22 @@ function func(declarations, functions, functionMatcher, parseArgs) { declarations.forEach(function(decl){ if ('comment' == decl.type) return; - var generatedFuncs = [], result, generatedFunc; + var replacedFunctions = [], replacedValues = [], result, replacedFunc, replacedValue; + + var colorFunctionRegexPart = "(?:rgb|hsl)a?"; + var colorMatcher = functionMatcherBuilder(colorFunctionRegexPart); + var replaceColorValues = function(value_str){ + while (value_str.match(colorMatcher)) { + value_str = value_str.replace(colorMatcher, function(color, name, args){ + replacedValue = {from: color, to: getRandomIdentifier(name)}; + replacedValues.push(replacedValue); + return replacedValue.to; + }); + } + return value_str; + }; + + decl.value = replaceColorValues(decl.value); while (decl.value.match(functionMatcher)) { decl.value = decl.value.replace(functionMatcher, function(_, name, args){ @@ -45,9 +60,17 @@ function func(declarations, functions, functionMatcher, parseArgs) { } else { args = [strip(args)]; } + args = args.map(function(arg){ + replacedValues.forEach(function(func) { + arg = arg.replace(func.to, func.from); + }); + return arg; + }); // Ensure result is string result = '' + functions[name].apply(decl, args); + result = replaceColorValues(result); + // Prevent fall into infinite loop like this: // // { @@ -56,16 +79,21 @@ function func(declarations, functions, functionMatcher, parseArgs) { // } // } // - generatedFunc = {from: name, to: name + getRandomString()}; - result = result.replace(functionMatcherBuilder(name), generatedFunc.to + '($2)'); - generatedFuncs.push(generatedFunc); + replacedFunc = {from: name, to: getRandomIdentifier(name)}; + result = result.replace(functionMatcherBuilder(name), replacedFunc.to + '($2)'); + replacedFunctions.push(replacedFunc); return result; }); } - generatedFuncs.forEach(function(func) { + replacedFunctions.forEach(function(func) { + decl.value = decl.value.replace(func.to, func.from); + }); + + replacedValues.forEach(function(func) { decl.value = decl.value.replace(func.to, func.from); - }) + }); + }); } @@ -82,13 +110,13 @@ function functionMatcherBuilder(name) { } /** - * get random string + * Generate a random string to use as an identifier replacing a function * * @api private */ -function getRandomString() { - return Math.random().toString(36).slice(2); +function getRandomIdentifier(name) { + return name + Math.random().toString(36).slice(2); } /** diff --git a/test/fixtures/function.colors.css b/test/fixtures/function.colors.css new file mode 100644 index 0000000..de9bea6 --- /dev/null +++ b/test/fixtures/function.colors.css @@ -0,0 +1,4 @@ +.colorful { + border-color: ugly-border(rgba(203,10,200,0.3),#1D1F21, hsl(320,50%,50%),hsla(230,90%,50%,0.7)); +} + diff --git a/test/fixtures/function.colors.nested.css b/test/fixtures/function.colors.nested.css new file mode 100644 index 0000000..2a9939e --- /dev/null +++ b/test/fixtures/function.colors.nested.css @@ -0,0 +1,4 @@ +.nested-color-calculation { + background-color: alpha(mix(#333, #FFF, 0.4), 0.8); +} + diff --git a/test/fixtures/function.colors.nested.out.css b/test/fixtures/function.colors.nested.out.css new file mode 100644 index 0000000..7d29a25 --- /dev/null +++ b/test/fixtures/function.colors.nested.out.css @@ -0,0 +1,4 @@ +.nested-color-calculation { + background-color: rgba(132, 132, 132, 0.8); +} + diff --git a/test/fixtures/function.colors.out.css b/test/fixtures/function.colors.out.css new file mode 100644 index 0000000..a25f3f3 --- /dev/null +++ b/test/fixtures/function.colors.out.css @@ -0,0 +1,4 @@ +.colorful { + border-color: rgba(203,10,200,0.3) #1D1F21 hsl(320,50%,50%) hsla(230,90%,50%,0.7); +} + diff --git a/test/rework-function.js b/test/rework-function.js index a7c1648..90f8c18 100644 --- a/test/rework-function.js +++ b/test/rework-function.js @@ -6,7 +6,10 @@ var rework = require('rework') , read = fs.readFileSync; function fixture(name) { - return read('test/fixtures/' + name + '.css', 'utf8').trim(); + return read('test/fixtures/' + name + '.css', 'utf8') + .trim() + .replace(/\r\n/g, "\n") + .replace(/\t/g, " "); } describe('.function()', function(){ @@ -50,4 +53,40 @@ describe('.function()', function(){ return 'url(' + '/some/prefix' + path + ')'; } }) + + it('should support (function-like) color values as parameters', function() { + + rework(fixture('function.colors')) + .use(func({"ugly-border": uglyBorder})) + .toString() + .should.equal(fixture('function.colors.out')); + + function uglyBorder(top, right, bottom, left){ + return top + ' ' + right + ' ' + bottom + ' ' + left; + } + }) + + it('should support (function-like) color values nested in parameters', function() { + + rework(fixture('function.colors.nested')) + .use(func({mix: mix, alpha: alpha})) + .toString() + .should.equal(fixture('function.colors.nested.out')); + + function mix(colorA, colorB, x){ + if(colorA === '#333' && colorB === '#FFF' && x == 0.4){ + return 'rgb(132, 132, 132)'; + }else{ + throw new Error('Unexpected arguments to mix(): ' + [colorA, colorB, x]); + } + } + + function alpha(color, x){ + if(color === 'rgb(132, 132, 132)' && x == 0.8){ + return 'rgba(132, 132, 132, 0.8)'; + }else{ + throw new Error('Unexpected arguments to alpha(): ' + [color, x]); + } + } + }) })