diff --git a/README.md b/README.md index ac4cb84c1..1776e88d7 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,8 @@ Note: If this option is provided to renderSync it will be ignored. In case of `r #### importer (starting from v2) `importer` is a `Function` to be called when libsass parser encounters the import directive. If present, libsass will call node-sass and let the user change file, data or both during the compilation. This option is optional, and applies to both render and renderSync functions. Also, it can either return object of form `{file:'..', contents: '..'}` or send it back via `done({})`. Note in renderSync or render, there is no restriction imposed on using `done()` callback or `return` statement (dispite of the asnchrony difference). +The options passed in to `render` and `renderSync` are available as `this.options` within the `Function`. + #### includePaths `includePaths` is an `Array` of path `String`s to look for any `@import`ed files. It is recommended that you use this option if you are using the `data` option and have **any** `@import` directives, as otherwise [libsass] may not find your depended-on files. diff --git a/lib/index.js b/lib/index.js index a11ec0f49..c5446e711 100644 --- a/lib/index.js +++ b/lib/index.js @@ -127,7 +127,6 @@ function getSourceMap(options) { * @param {Object} options * @api private */ - function getOptions(options) { options = options || {}; options.comments = options.source_comments || options.sourceComments || false; @@ -140,6 +139,9 @@ function getOptions(options) { options.sourceMap = getSourceMap(options); options.style = getStyle(options) || 0; + // context object represents node-sass environment + options.context = { options: options }; + if (options.imagePath && typeof options.imagePath !== 'string') { throw new Error('`imagePath` needs to be a string'); } @@ -149,7 +151,7 @@ function getOptions(options) { options.error = function(err) { if (error) { - error(util._extend(new Error(), JSON.parse(err))); + error.call(options.context, util._extend(new Error(), JSON.parse(err))); } }; @@ -158,7 +160,7 @@ function getOptions(options) { var stats = endStats(result.stats); if (success) { - success({ + success.call(options.context, { css: result.css, map: result.map, stats: stats @@ -207,7 +209,7 @@ module.exports.render = function(options) { }); } - var result = importer(file, prev, done); + var result = importer.call(options.context, file, prev, done); if (result) { done(result); @@ -232,7 +234,7 @@ module.exports.renderSync = function(options) { if (importer) { options.importer = function(file, prev) { - return { objectLiteral: importer(file, prev) }; + return { objectLiteral: importer.call(options.context, file, prev) }; }; } diff --git a/test/api.js b/test/api.js index 2a37c12db..5c2416f96 100644 --- a/test/api.js +++ b/test/api.js @@ -299,7 +299,7 @@ describe('api', function() { } }); }); - + it('should override imports with "data" as input and fires callback with contents', function(done) { sass.render({ data: src, @@ -359,6 +359,56 @@ describe('api', function() { } }); }); + + it('should be able to see its options in this.options', function(done) { + var fxt = fixture('include-files/index.scss'); + sass.render({ + file: fxt, + success: function() { + assert.equal(fxt, this.options.file); + done(); + }, + importer: function() { + assert.equal(fxt, this.options.file); + return {}; + } + }); + }); + + it('should be able to access a persistent options object', function(done) { + sass.render({ + data: src, + success: function() { + assert.equal(this.state, 2); + done(); + }, + importer: function() { + this.state = this.state || 0; + this.state++; + return { + contents: 'div {color: yellow;}' + }; + } + }); + }); + + it('should copy all options properties', function(done) { + var options; + options = { + data: src, + success: function() { + assert.strictEqual(this.options.success, options.success); + done(); + }, + importer: function() { + assert.strictEqual(this.options.importer, options.importer); + return { + contents: 'div {color: yellow;}' + }; + } + }; + sass.render(options); + }); }); describe('.renderSync(options)', function() { @@ -493,7 +543,7 @@ describe('api', function() { assert.equal(result.css.trim(), ''); done(); }); - + it('should override imports with "data" as input and returns contents', function(done) { var result = sass.renderSync({ data: src, @@ -521,6 +571,21 @@ describe('api', function() { assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); done(); }); + + it('should be able to see its options in this.options', function(done) { + var fxt = fixture('include-files/index.scss'); + var sync = false; + sass.renderSync({ + file: fixture('include-files/index.scss'), + importer: function() { + assert.equal(fxt, this.options.file); + sync = true; + return {}; + } + }); + assert.equal(sync, true); + done(); + }); }); describe('.render({stats: {}})', function() { @@ -713,8 +778,8 @@ describe('api', function() { describe('.info()', function() { it('should return a correct version info', function(done) { assert.equal(sass.info(), [ - 'node-sass version: ' + require('../package.json').version, - 'libsass version: ' + require('../package.json').libsass + 'node-sass version: ' + require('../package.json').version, + 'libsass version: ' + require('../package.json').libsass ].join('\n')); done();