Commit 69a45603 by Jakob Heuser

Adding a backwards compatible node-style callback

This is node-style callbacks for #676. This allows us to release
the new callback style without introducing backwards incompatible
changes (or making changes to the binary from 2.0.1). If a node style
callback is provided, it will be used. For now, this stacks with
the original `options.success` and `options.error`, although it can
be trivially changed to an xor.

To highlight the new interface, a separate `describe` was added to the
tests which identifies the `{options}, cb` interface and tests it
independently.
parent 92456685
...@@ -54,9 +54,8 @@ Compiling versions 0.9.4 and above on Windows machines requires [Visual Studio 2 ...@@ -54,9 +54,8 @@ Compiling versions 0.9.4 and above on Windows machines requires [Visual Studio 2
var sass = require('node-sass'); var sass = require('node-sass');
sass.render({ sass.render({
file: scss_filename, file: scss_filename,
success: callback
[, options..] [, options..]
}); }, function(err, result) { /*...*/ });
// OR // OR
var result = sass.renderSync({ var result = sass.renderSync({
data: scss_content data: scss_content
...@@ -66,7 +65,7 @@ var result = sass.renderSync({ ...@@ -66,7 +65,7 @@ var result = sass.renderSync({
### Options ### Options
The API for using node-sass has changed, so that now there is only one variable - an options hash. Some of these options are optional, and in some circumstances some are mandatory. The API for using node-sass has changed, so that now there is only one options hash. In the options hash, some items are optional, others may be mandatory depending on circumstances.
#### file #### file
`file` is a `String` of the path to an `scss` file for [libsass] to render. One of this or `data` options are required, for both render and renderSync. `file` is a `String` of the path to an `scss` file for [libsass] to render. One of this or `data` options are required, for both render and renderSync.
...@@ -140,6 +139,26 @@ You must define this option as well as `outFile` in order to generate a source m ...@@ -140,6 +139,26 @@ You must define this option as well as `outFile` in order to generate a source m
#### sourceMapContents #### sourceMapContents
`sourceMapContents` is a `Boolean` flag to determine whether to include `contents` in maps. `sourceMapContents` is a `Boolean` flag to determine whether to include `contents` in maps.
### The `render` Callback (starting from v2.1)
node-sass supports standard node style asynchronous callbacks with the signature of `function(err, result)`. In error conditions, the `error` argument is populated with the error object. In success conditions, the `result` object is populated with an object describing the result of the render call.
#### The Error Object
* `message` - The error message.
* `line` - The line number of error.
* `column` - The column number of error.
* `status` - The status code.
* `file` - The filename of error. In case `file` option was not set (in favour of `data`), this will reflect the value `stdin`.
#### The Result Object
* `css` - The compiled CSS. Write this to a file, or serve it out as needed.
* `map` - The source map
* `stats` - An object containing information about the compile. It contains the following keys:
* `entry` - The path to the scss file, or `data` if the source was not a file
* `start` - Date.now() before the compilation
* `end` - Date.now() after the compilation
* `duration` - *end* - *start*
* `includedFiles` - Absolute paths to all related scss files in no particular order.
### Examples ### Examples
```javascript ```javascript
...@@ -147,19 +166,19 @@ var sass = require('node-sass'); ...@@ -147,19 +166,19 @@ var sass = require('node-sass');
sass.render({ sass.render({
file: '/path/to/myFile.scss', file: '/path/to/myFile.scss',
data: 'body{background:blue; a{color:black;}}', data: 'body{background:blue; a{color:black;}}',
success: function(result) { success: function(result) {
// result is an object: v2 change // result is an object: v2 change
console.log(result.css); console.log(result.css);
console.log(result.stats); console.log(result.stats);
console.log(result.map) console.log(result.map)
}, },
error: function(error) { // starting v2.1 error is an Error-typed object error: function(error) { // starting v2.1 error is an Error-typed object
// error is an object: v2 change // error is an object: v2 change
console.log(error.message); console.log(error.message);
console.log(error.status); // changed from code to status in v2.1 console.log(error.status); // changed from code to status in v2.1
console.log(error.line); console.log(error.line);
console.log(error.column); // new in v2 console.log(error.column); // new in v2
}, },
importer: function(url, prev, done) { importer: function(url, prev, done) {
// url is the path in import as is, which libsass encountered. // url is the path in import as is, which libsass encountered.
// prev is the previously resolved path. // prev is the previously resolved path.
...@@ -176,6 +195,10 @@ sass.render({ ...@@ -176,6 +195,10 @@ sass.render({
}, },
includePaths: [ 'lib/', 'mod/' ], includePaths: [ 'lib/', 'mod/' ],
outputStyle: 'compressed' outputStyle: 'compressed'
}, function(error, result) {
// starting v2.1 the node-style callback has error (Object) and result (Object)
// the objects are identical to those provided for the error and success keys
// in the options object
}); });
// OR // OR
var result = sass.renderSync({ var result = sass.renderSync({
......
...@@ -127,7 +127,7 @@ function getSourceMap(options) { ...@@ -127,7 +127,7 @@ function getSourceMap(options) {
* @param {Object} options * @param {Object} options
* @api private * @api private
*/ */
function getOptions(options) { function getOptions(options, cb) {
options = options || {}; options = options || {};
options.comments = options.source_comments || options.sourceComments || false; options.comments = options.source_comments || options.sourceComments || false;
options.data = options.data || null; options.data = options.data || null;
...@@ -150,21 +150,30 @@ function getOptions(options) { ...@@ -150,21 +150,30 @@ function getOptions(options) {
var success = options.success; var success = options.success;
options.error = function(err) { options.error = function(err) {
var payload = util._extend(new Error(), JSON.parse(err));
if (cb) {
cb.call(options.context, payload, null);
}
if (error) { if (error) {
error.call(options.context, util._extend(new Error(), JSON.parse(err))); error.call(options.context, payload);
} }
}; };
options.success = function() { options.success = function() {
var result = options.result; var result = options.result;
var stats = endStats(result.stats); var stats = endStats(result.stats);
var payload = {
css: result.css,
map: result.map,
stats: stats
};
if (cb) {
cb.call(options.context, null, payload);
}
if (success) { if (success) {
success.call(options.context, { success.call(options.context, payload);
css: result.css,
map: result.map,
stats: stats
});
} }
}; };
...@@ -194,8 +203,8 @@ var binding = require(getBinding()); ...@@ -194,8 +203,8 @@ var binding = require(getBinding());
* @api public * @api public
*/ */
module.exports.render = function(options) { module.exports.render = function(options, cb) {
options = getOptions(options); options = getOptions(options, cb);
var importer = options.importer; var importer = options.importer;
...@@ -243,7 +252,6 @@ module.exports.renderSync = function(options) { ...@@ -243,7 +252,6 @@ module.exports.renderSync = function(options) {
if(status) { if(status) {
result.stats = endStats(result.stats); result.stats = endStats(result.stats);
return result; return result;
} }
......
...@@ -411,6 +411,28 @@ describe('api', function() { ...@@ -411,6 +411,28 @@ describe('api', function() {
}); });
}); });
describe('.render(options, cb)', function() {
it('should compile sass to css with file', function(done) {
var expected = 'div {\n color: yellow; }';
sass.render({
data: 'div {color: yellow;}'
}, function(err, result) {
assert.equal(result.css.trim(), expected);
done();
});
});
it('should throw error status 1 for bad input', function(done) {
sass.render({
data: '#navbar width 80%;'
}, function(err) {
assert(err.message);
assert.equal(err.status, 1);
done();
});
});
});
describe('.renderSync(options)', function() { describe('.renderSync(options)', function() {
it('should compile sass to css with file', function(done) { it('should compile sass to css with file', function(done) {
var expected = read(fixture('simple/expected.css'), 'utf8').trim(); var expected = read(fixture('simple/expected.css'), 'utf8').trim();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment