Commit 0a4970e4 by Adeel

API: Encapsulate output in a single object.

parent 70ce07ba
...@@ -54,7 +54,7 @@ function getOutFile(options) { ...@@ -54,7 +54,7 @@ function getOutFile(options) {
*/ */
function getStats(options) { function getStats(options) {
var stats = options.stats; var stats = {};
stats.entry = options.file || 'data'; stats.entry = options.file || 'data';
stats.start = Date.now(); stats.start = Date.now();
...@@ -70,12 +70,11 @@ function getStats(options) { ...@@ -70,12 +70,11 @@ function getStats(options) {
* @api private * @api private
*/ */
function endStats(options, sourceMap) { function endStats(options) {
var stats = options.stats || {}; var stats = options.stats || {};
stats.end = Date.now(); stats.end = Date.now();
stats.duration = stats.end - stats.start; stats.duration = stats.end - stats.start;
stats.sourceMap = sourceMap;
return stats; return stats;
} }
...@@ -139,14 +138,13 @@ function getOptions(options) { ...@@ -139,14 +138,13 @@ function getOptions(options) {
options.paths = (options.include_paths || options.includePaths || []).join(path.delimiter); options.paths = (options.include_paths || options.includePaths || []).join(path.delimiter);
options.precision = parseInt(options.precision) || 5; options.precision = parseInt(options.precision) || 5;
options.sourceMap = getSourceMap(options); options.sourceMap = getSourceMap(options);
options.stats = options.stats || {};
options.style = getStyle(options) || 0; options.style = getStyle(options) || 0;
if (options.imagePath && typeof options.imagePath !== 'string') { if (options.imagePath && typeof options.imagePath !== 'string') {
throw new Error('`imagePath` needs to be a string'); throw new Error('`imagePath` needs to be a string');
} }
getStats(options); options.stats = getStats(options);
var error = options.error; var error = options.error;
var success = options.success; var success = options.success;
...@@ -159,8 +157,10 @@ function getOptions(options) { ...@@ -159,8 +157,10 @@ function getOptions(options) {
err = { message: err }; err = { message: err };
} }
err.code = code;
if (error) { if (error) {
error(err, code); error(err);
} }
}; };
...@@ -170,7 +170,11 @@ function getOptions(options) { ...@@ -170,7 +170,11 @@ function getOptions(options) {
endStats(options, sourceMap); endStats(options, sourceMap);
if (success) { if (success) {
success(css, sourceMap); success({
css: css,
map: sourceMap,
stats: options.stats
});
} }
}; };
...@@ -225,77 +229,16 @@ module.exports.renderSync = function(options) { ...@@ -225,77 +229,16 @@ module.exports.renderSync = function(options) {
options = getOptions(options); options = getOptions(options);
output = options.data ? binding.renderSync(options) : binding.renderFileSync(options); output = options.data ? binding.renderSync(options) : binding.renderFileSync(options);
endStats(options, JSON.parse(options.stats.sourceMap)); endStats(options);
return output;
};
/**
* Render file
*
* `options.sourceMap` can be used to specify that the source map should be saved:
*
* - If falsy the source map will not be saved
* - If `options.sourceMap === true` the source map will be saved to the
* standard location of `options.file + '.map'`
* - Else `options.sourceMap` specifies the path (relative to the `outFile`)
* where the source map should be saved
*
* @param {Object} options
* @api public
*/
module.exports.renderFile = function(options) {
options = options || {};
var outFile = options.outFile;
var success = options.success;
if (options.sourceMap === true) {
options.sourceMap = outFile + '.map';
}
options.success = function(css, sourceMap) {
fs.writeFile(outFile, css, function(err) {
if (err) {
return options.error(err);
}
if (!options.sourceMap) {
return success(outFile);
}
var dir = path.dirname(outFile);
var sourceMapFile = path.resolve(dir, options.sourceMap);
fs.writeFile(sourceMapFile, JSON.stringify(sourceMap), function(err) {
if (err) {
return options.error(err);
}
success(outFile, sourceMapFile); var result = {
}); css: output,
}); map: options.stats.sourceMap
}; };
module.exports.render(options); delete options.stats.sourceMap;
};
/**
* Middleware
*
* @api public
*/
module.exports.middleware = function() { result.stats = options.stats;
return new Error([
'The middleware has been moved to',
'https://github.com/sass/node-sass-middleware'
].join(' '));
endStats(options, options.stats.sourceMap); return result;
return {
css: output,
map: options.stats.sourceMap
};
}; };
...@@ -31,7 +31,7 @@ module.exports = function(options, emitter) { ...@@ -31,7 +31,7 @@ module.exports = function(options, emitter) {
renderOptions.data = options.data; renderOptions.data = options.data;
} }
renderOptions.success = function(css, sourceMap) { renderOptions.success = function(result) {
var todo = 1; var todo = 1;
var done = function() { var done = function() {
if (--todo <= 0) { if (--todo <= 0) {
...@@ -40,37 +40,37 @@ module.exports = function(options, emitter) { ...@@ -40,37 +40,37 @@ module.exports = function(options, emitter) {
}; };
if (options.stdout || (!options.dest && !process.stdout.isTTY) || options.stdin) { if (options.stdout || (!options.dest && !process.stdout.isTTY) || options.stdin) {
emitter.emit('log', css); emitter.emit('log', result.css);
return done(); return done();
} }
emitter.emit('warn', chalk.green('Rendering Complete, saving .css file...')); emitter.emit('warn', chalk.green('Rendering Complete, saving .css file...'));
fs.writeFile(options.dest, css, function(err) { fs.writeFile(options.dest, result.css, function(err) {
if (err) { if (err) {
return emitter.emit('error', chalk.red(err)); return emitter.emit('error', chalk.red(err));
} }
emitter.emit('warn', chalk.green('Wrote CSS to ' + options.dest)); emitter.emit('warn', chalk.green('Wrote CSS to ' + options.dest));
emitter.emit('write', err, options.dest, css); emitter.emit('write', err, options.dest, result.css);
done(); done();
}); });
if (options.sourceMap) { if (options.sourceMap) {
todo++; todo++;
fs.writeFile(options.sourceMap, sourceMap, function(err) { fs.writeFile(options.sourceMap, result.map, function(err) {
if (err) { if (err) {
return emitter.emit('error', chalk.red('Error' + err)); return emitter.emit('error', chalk.red('Error' + err));
} }
emitter.emit('warn', chalk.green('Wrote Source Map to ' + options.sourceMap)); emitter.emit('warn', chalk.green('Wrote Source Map to ' + options.sourceMap));
emitter.emit('write-source-map', err, options.sourceMap, sourceMap); emitter.emit('write-source-map', err, options.sourceMap, result.sourceMap);
done(); done();
}); });
} }
emitter.emit('render', css); emitter.emit('render', result.css);
}; };
renderOptions.error = function(error) { renderOptions.error = function(error) {
......
...@@ -14,8 +14,8 @@ describe('api', function() { ...@@ -14,8 +14,8 @@ describe('api', function() {
sass.render({ sass.render({
data: src, data: src,
success: function(css) { success: function(result) {
assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n'));
done(); done();
} }
}); });
...@@ -28,8 +28,8 @@ describe('api', function() { ...@@ -28,8 +28,8 @@ describe('api', function() {
sass.render({ sass.render({
data: src, data: src,
indentedSyntax: true, indentedSyntax: true,
success: function(css) { success: function(result) {
assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n'));
done(); done();
} }
}); });
...@@ -38,9 +38,9 @@ describe('api', function() { ...@@ -38,9 +38,9 @@ describe('api', function() {
it('should throw error status 1 for bad input', function(done) { it('should throw error status 1 for bad input', function(done) {
sass.render({ sass.render({
data: '#navbar width 80%;', data: '#navbar width 80%;',
error: function(err, status) { error: function(error) {
assert(err); assert(error.message);
assert.equal(status, 1); assert.equal(error.status, 1);
done(); done();
} }
}); });
...@@ -56,8 +56,8 @@ describe('api', function() { ...@@ -56,8 +56,8 @@ describe('api', function() {
fixture('include-path/functions'), fixture('include-path/functions'),
fixture('include-path/lib') fixture('include-path/lib')
], ],
success: function(css) { success: function(result) {
assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n'));
done(); done();
} }
}); });
...@@ -70,8 +70,8 @@ describe('api', function() { ...@@ -70,8 +70,8 @@ describe('api', function() {
sass.render({ sass.render({
data: src, data: src,
imagePath: '/path/to/images', imagePath: '/path/to/images',
success: function(css) { success: function(result) {
assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n'));
done(); done();
} }
}); });
...@@ -97,8 +97,8 @@ describe('api', function() { ...@@ -97,8 +97,8 @@ describe('api', function() {
sass.render({ sass.render({
data: src, data: src,
precision: 10, precision: 10,
success: function(css) { success: function(result) {
assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n'));
done(); done();
} }
}); });
...@@ -106,14 +106,12 @@ describe('api', function() { ...@@ -106,14 +106,12 @@ describe('api', function() {
it('should compile with stats', function(done) { it('should compile with stats', function(done) {
var src = fixture('precision/index.scss'); var src = fixture('precision/index.scss');
var stats = {};
sass.render({ sass.render({
file: src, file: src,
stats: stats,
sourceMap: true, sourceMap: true,
success: function() { success: function(result) {
assert.equal(stats.entry, src); assert.equal(result.stats.entry, src);
done(); done();
} }
}); });
...@@ -121,7 +119,6 @@ describe('api', function() { ...@@ -121,7 +119,6 @@ describe('api', function() {
it('should contain all included files in stats when data is passed', function(done) { it('should contain all included files in stats when data is passed', function(done) {
var src = fixture('include-files/index.scss'); var src = fixture('include-files/index.scss');
var stats = {};
var expected = [ var expected = [
fixture('include-files/bar.scss').replace(/\\/g, '/'), fixture('include-files/bar.scss').replace(/\\/g, '/'),
fixture('include-files/foo.scss').replace(/\\/g, '/') fixture('include-files/foo.scss').replace(/\\/g, '/')
...@@ -130,9 +127,8 @@ describe('api', function() { ...@@ -130,9 +127,8 @@ describe('api', function() {
sass.render({ sass.render({
data: read(src, 'utf8'), data: read(src, 'utf8'),
includePaths: [fixture('include-files')], includePaths: [fixture('include-files')],
stats: stats, success: function(result) {
success: function() { assert.deepEqual(result.stats.includedFiles, expected);
assert.deepEqual(stats.includedFiles, expected);
done(); done();
} }
}); });
...@@ -143,9 +139,9 @@ describe('api', function() { ...@@ -143,9 +139,9 @@ describe('api', function() {
it('should compile sass to css', function(done) { it('should compile sass to css', function(done) {
var src = read(fixture('simple/index.scss'), 'utf8'); var src = read(fixture('simple/index.scss'), 'utf8');
var expected = read(fixture('simple/expected.css'), 'utf8').trim(); var expected = read(fixture('simple/expected.css'), 'utf8').trim();
var css = sass.renderSync({data: src}).css.trim(); var result = sass.renderSync({data: src});
assert.equal(css, expected.replace(/\r\n/g, '\n')); assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n'));
done(); done();
}); });
...@@ -172,13 +168,13 @@ describe('api', function() { ...@@ -172,13 +168,13 @@ describe('api', function() {
describe('.render({stats: {}})', function() { describe('.render({stats: {}})', function() {
var start = Date.now(); var start = Date.now();
var stats = {};
before(function(done) { it('should provide a start timestamp', function(done) {
sass.render({ sass.render({
file: fixture('include-files/index.scss'), file: fixture('include-files/index.scss'),
stats: stats, success: function(result) {
success: function() { assert(typeof result.stats.start === 'number');
assert(result.stats.start >= start);
done(); done();
}, },
error: function(err) { error: function(err) {
...@@ -188,27 +184,48 @@ describe('api', function() { ...@@ -188,27 +184,48 @@ describe('api', function() {
}); });
}); });
it('should provide a start timestamp', function(done) {
assert(typeof stats.start === 'number');
assert(stats.start >= start);
done();
});
it('should provide an end timestamp', function(done) { it('should provide an end timestamp', function(done) {
assert(typeof stats.end === 'number'); sass.render({
assert(stats.end >= stats.start); file: fixture('include-files/index.scss'),
done(); success: function(result) {
assert(typeof result.stats.end === 'number');
assert(result.stats.end >= result.stats.start);
done();
},
error: function(err) {
assert(!err);
done();
}
});
}); });
it('should provide a duration', function(done) { it('should provide a duration', function(done) {
assert(typeof stats.duration === 'number'); sass.render({
assert.equal(stats.end - stats.start, stats.duration); file: fixture('include-files/index.scss'),
done(); success: function(result) {
assert(typeof result.stats.duration === 'number');
assert.equal(result.stats.end - result.stats.start, result.stats.duration);
done();
},
error: function(err) {
assert(!err);
done();
}
});
}); });
it('should contain the given entry file', function(done) { it('should contain the given entry file', function(done) {
assert.equal(stats.entry, fixture('include-files/index.scss')); sass.render({
done(); file: fixture('include-files/index.scss'),
success: function(result) {
assert.equal(result.stats.entry, fixture('include-files/index.scss'));
done();
},
error: function(err) {
assert(!err);
done();
}
});
}); });
it('should contain an array of all included files', function(done) { it('should contain an array of all included files', function(done) {
...@@ -218,8 +235,17 @@ describe('api', function() { ...@@ -218,8 +235,17 @@ describe('api', function() {
fixture('include-files/index.scss').replace(/\\/g, '/') fixture('include-files/index.scss').replace(/\\/g, '/')
]; ];
assert.deepEqual(stats.includedFiles, expected); sass.render({
done(); file: fixture('include-files/index.scss'),
success: function(result) {
assert.deepEqual(result.stats.includedFiles, expected);
done();
},
error: function(err) {
assert(!err);
done();
}
});
}); });
it('should contain array with the entry if there are no import statements', function(done) { it('should contain array with the entry if there are no import statements', function(done) {
...@@ -227,9 +253,8 @@ describe('api', function() { ...@@ -227,9 +253,8 @@ describe('api', function() {
sass.render({ sass.render({
file: fixture('simple/index.scss'), file: fixture('simple/index.scss'),
stats: stats, success: function(result) {
success: function() { assert.deepEqual(result.stats.includedFiles, [expected]);
assert.deepEqual(stats.includedFiles, [expected]);
done(); done();
} }
}); });
...@@ -238,9 +263,8 @@ describe('api', function() { ...@@ -238,9 +263,8 @@ describe('api', function() {
it('should state `data` as entry file', function(done) { it('should state `data` as entry file', function(done) {
sass.render({ sass.render({
data: read(fixture('simple/index.scss'), 'utf8'), data: read(fixture('simple/index.scss'), 'utf8'),
stats: stats, success: function(result) {
success: function() { assert.equal(result.stats.entry, 'data');
assert.equal(stats.entry, 'data');
done(); done();
} }
}); });
...@@ -249,22 +273,8 @@ describe('api', function() { ...@@ -249,22 +273,8 @@ describe('api', function() {
it('should contain an empty array as includedFiles', function(done) { it('should contain an empty array as includedFiles', function(done) {
sass.render({ sass.render({
data: read(fixture('simple/index.scss'), 'utf8'), data: read(fixture('simple/index.scss'), 'utf8'),
stats: stats, success: function(result) {
success: function() { assert.deepEqual(result.stats.includedFiles, []);
assert.deepEqual(stats.includedFiles, []);
done();
}
});
});
it('should report correct source map in stats', function(done) {
sass.render({
file: fixture('simple/index.scss'),
outFile: fixture('simple/build.css'),
stats: stats,
sourceMap: true,
success: function() {
assert.equal(stats.sourceMap.sources[0], 'index.scss');
done(); done();
} }
}); });
...@@ -273,35 +283,30 @@ describe('api', function() { ...@@ -273,35 +283,30 @@ describe('api', function() {
describe('.renderSync({stats: {}})', function() { describe('.renderSync({stats: {}})', function() {
var start = Date.now(); var start = Date.now();
var stats = {}; var result = sass.renderSync({
file: fixture('include-files/index.scss')
before(function() {
sass.renderSync({
file: fixture('include-files/index.scss'),
stats: stats
});
}); });
it('should provide a start timestamp', function(done) { it('should provide a start timestamp', function(done) {
assert(typeof stats.start === 'number'); assert(typeof result.stats.start === 'number');
assert(stats.start >= start); assert(result.stats.start >= start);
done(); done();
}); });
it('should provide an end timestamp', function(done) { it('should provide an end timestamp', function(done) {
assert(typeof stats.end === 'number'); assert(typeof result.stats.end === 'number');
assert(stats.end >= stats.start); assert(result.stats.end >= result.stats.start);
done(); done();
}); });
it('should provide a duration', function(done) { it('should provide a duration', function(done) {
assert(typeof stats.duration === 'number'); assert(typeof result.stats.duration === 'number');
assert.equal(stats.end - stats.start, stats.duration); assert.equal(result.stats.end - result.stats.start, result.stats.duration);
done(); done();
}); });
it('should contain the given entry file', function(done) { it('should contain the given entry file', function(done) {
assert.equal(stats.entry, resolveFixture('include-files/index.scss')); assert.equal(result.stats.entry, resolveFixture('include-files/index.scss'));
done(); done();
}); });
...@@ -312,53 +317,38 @@ describe('api', function() { ...@@ -312,53 +317,38 @@ describe('api', function() {
fixture('include-files/index.scss').replace(/\\/g, '/') fixture('include-files/index.scss').replace(/\\/g, '/')
]; ];
assert.equal(stats.includedFiles[0], expected[0]); assert.equal(result.stats.includedFiles[0], expected[0]);
assert.equal(stats.includedFiles[1], expected[1]); assert.equal(result.stats.includedFiles[1], expected[1]);
assert.equal(stats.includedFiles[2], expected[2]); assert.equal(result.stats.includedFiles[2], expected[2]);
done(); done();
}); });
it('should contain array with the entry if there are no import statements', function(done) { it('should contain array with the entry if there are no import statements', function(done) {
var expected = fixture('simple/index.scss').replace(/\\/g, '/'); var expected = fixture('simple/index.scss').replace(/\\/g, '/');
sass.renderSync({ var result = sass.renderSync({
file: fixture('simple/index.scss'), file: fixture('simple/index.scss')
stats: stats
}); });
assert.deepEqual(stats.includedFiles, [expected]); assert.deepEqual(result.stats.includedFiles, [expected]);
done(); done();
}); });
it('should state `data` as entry file', function(done) { it('should state `data` as entry file', function(done) {
sass.renderSync({ var result = sass.renderSync({
data: read(fixture('simple/index.scss'), 'utf8'), data: read(fixture('simple/index.scss'), 'utf8')
stats: stats
}); });
assert.equal(stats.entry, 'data'); assert.equal(result.stats.entry, 'data');
done(); done();
}); });
it('should contain an empty array as includedFiles', function(done) { it('should contain an empty array as includedFiles', function(done) {
sass.renderSync({ var result = sass.renderSync({
data: read(fixture('simple/index.scss'), 'utf8'), data: read(fixture('simple/index.scss'), 'utf8')
stats: stats
});
assert.deepEqual(stats.includedFiles, []);
done();
});
it('should report correct source map in stats', function(done) {
sass.renderSync({
file: fixture('simple/index.scss'),
outFile: fixture('simple/build.css'),
stats: stats,
sourceMap: true
}); });
assert.equal(stats.sourceMap.sources[0], 'index.scss'); assert.deepEqual(result.stats.includedFiles, []);
done(); done();
}); });
}); });
......
...@@ -40,8 +40,8 @@ describe('spec', function () { ...@@ -40,8 +40,8 @@ describe('spec', function () {
sass.render({ sass.render({
file: t.src, file: t.src,
includePaths: t.paths, includePaths: t.paths,
success: function(css) { success: function(result) {
assert.equal(util.normalize(css), expected); assert.equal(util.normalize(result.css), expected);
done(); done();
}, },
error: function(err) { error: function(err) {
......
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