Commit 0a4970e4 by Adeel

API: Encapsulate output in a single object.

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