diff --git a/README.md b/README.md index 42b7d725a..73da0a789 100644 --- a/README.md +++ b/README.md @@ -452,7 +452,8 @@ Output will be saved with the same name as input SASS file into the current work --source-map-root Base path, will be emitted in source-map as is --include-path Path to look for imported files --precision The amount of precision allowed in decimal numbers - --importer Path to custom importer + --importer Path to .js file containing custom importer + --functions Path to .js file containing custom functions --help Print usage info ``` diff --git a/bin/node-sass b/bin/node-sass index f0a548351..f85043271 100755 --- a/bin/node-sass +++ b/bin/node-sass @@ -42,7 +42,8 @@ var cli = meow({ ' --source-map-root Base path, will be emitted in source-map as is', ' --include-path Path to look for imported files', ' --precision The amount of precision allowed in decimal numbers', - ' --importer Path to custom importer', + ' --importer Path to .js file containing custom importer', + ' --functions Path to .js file containing custom functions', ' --help Print usage info' ].join('\n') }, { @@ -55,6 +56,8 @@ var cli = meow({ 'source-comments' ], string: [ + 'functions', + 'importer', 'include-path', 'indent-type', 'linefeed', @@ -227,6 +230,14 @@ function run(options, emitter) { } } + if (options.functions) { + if ((path.resolve(options.functions) === path.normalize(options.functions).replace(/(.+)([\/|\\])$/, '$1'))) { + options.functions = require(options.functions); + } else { + options.functions = require(path.resolve(process.cwd(), options.functions)); + } + } + if (options.watch) { watch(options, emitter); } else { diff --git a/lib/render.js b/lib/render.js index ae7f0b226..28e41a181 100644 --- a/lib/render.js +++ b/lib/render.js @@ -30,6 +30,7 @@ module.exports = function(options, emitter) { sourceMap: options.sourceMap, sourceMapRoot: options.sourceMapRoot, importer: options.importer, + functions: options.functions, indentWidth: options.indentWidth, indentType: options.indentType, linefeed: options.linefeed diff --git a/test/cli.js b/test/cli.js index fc3c0a1b7..16476e893 100644 --- a/test/cli.js +++ b/test/cli.js @@ -400,4 +400,38 @@ describe('cli', function() { }); }); }); + + describe('functions', function() { + it('should let custom functions call setter methods on wrapped sass values (number)', function(done) { + var dest = fixture('custom-functions/setter.css'); + var src = fixture('custom-functions/setter.scss'); + var expected = read(fixture('custom-functions/setter-expected.css'), 'utf8').trim().replace(/\r\n/g, '\n'); + var bin = spawn(cli, [ + src, '--output', path.dirname(dest), + '--functions', fixture('extras/my_custom_functions_setter.js') + ]); + + bin.once('close', function() { + assert.equal(read(dest, 'utf8').trim(), expected); + fs.unlinkSync(dest); + done(); + }); + }); + + it('should properly convert strings when calling custom functions', function(done) { + var dest = fixture('custom-functions/string-conversion.css'); + var src = fixture('custom-functions/string-conversion.scss'); + var expected = read(fixture('custom-functions/string-conversion-expected.css'), 'utf8').trim().replace(/\r\n/g, '\n'); + var bin = spawn(cli, [ + src, '--output', path.dirname(dest), + '--functions', fixture('extras/my_custom_functions_string_conversion.js') + ]); + + bin.once('close', function() { + assert.equal(read(dest, 'utf8').trim(), expected); + fs.unlinkSync(dest); + done(); + }); + }); + }); }); diff --git a/test/fixtures/custom-functions/setter-expected.css b/test/fixtures/custom-functions/setter-expected.css new file mode 100644 index 000000000..9b67ea9aa --- /dev/null +++ b/test/fixtures/custom-functions/setter-expected.css @@ -0,0 +1,3 @@ +div { + width: 42rem; + height: 84px; } diff --git a/test/fixtures/custom-functions/setter.scss b/test/fixtures/custom-functions/setter.scss new file mode 100644 index 000000000..fbc6116b1 --- /dev/null +++ b/test/fixtures/custom-functions/setter.scss @@ -0,0 +1 @@ +div { width: foo(42px); height: bar(42px); } diff --git a/test/fixtures/custom-functions/string-conversion-expected.css b/test/fixtures/custom-functions/string-conversion-expected.css new file mode 100644 index 000000000..741d2cb50 --- /dev/null +++ b/test/fixtures/custom-functions/string-conversion-expected.css @@ -0,0 +1,2 @@ +div { + color: "barbar"; } diff --git a/test/fixtures/custom-functions/string-conversion.scss b/test/fixtures/custom-functions/string-conversion.scss new file mode 100644 index 000000000..4e6403f16 --- /dev/null +++ b/test/fixtures/custom-functions/string-conversion.scss @@ -0,0 +1 @@ +div { color: foo("bar"); } diff --git a/test/fixtures/extras/my_custom_functions_setter.js b/test/fixtures/extras/my_custom_functions_setter.js new file mode 100644 index 000000000..9ec8c24e5 --- /dev/null +++ b/test/fixtures/extras/my_custom_functions_setter.js @@ -0,0 +1,10 @@ +module.exports = { + 'foo($a)': function(size) { + size.setUnit('rem'); + return size; + }, + 'bar($a)': function(size) { + size.setValue(size.getValue() * 2); + return size; + } +}; diff --git a/test/fixtures/extras/my_custom_functions_string_conversion.js b/test/fixtures/extras/my_custom_functions_string_conversion.js new file mode 100644 index 000000000..3aa4eb8fe --- /dev/null +++ b/test/fixtures/extras/my_custom_functions_string_conversion.js @@ -0,0 +1,8 @@ +var sass = require('../../..'); + +module.exports = { + 'foo($a)': function(str) { + str = str.getValue().replace(/['"]/g, ''); + return new sass.types.String('"' + str + str + '"'); + } +};