Commit 51f472fe by Johannes Ewald

Add stats-object

parent d9058348
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
using namespace v8; using namespace v8;
using namespace std; using namespace std;
void WorkOnContext(uv_work_t* req) { void WorkOnContext(uv_work_t* req) {
sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data); sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data);
if (ctx_w->ctx) { if (ctx_w->ctx) {
...@@ -20,19 +19,18 @@ void WorkOnContext(uv_work_t* req) { ...@@ -20,19 +19,18 @@ void WorkOnContext(uv_work_t* req) {
} }
} }
char* CreateString(Handle<Value> arg) { char* CreateString(Local<Value> value) {
String::AsciiValue str(arg); size_t count;
char* newStr = new char[str.length() + 1]; return NanCString(value, &count);
strcpy(newStr, *str);
return newStr;
} }
void extractOptions(_NAN_METHOD_ARGS, void* cptr, sass_context_wrapper* ctx_w, bool isFile) { void ExtractOptions(Local<Value> optionsValue, void* cptr, sass_context_wrapper* ctx_w, bool isFile) {
int source_comments; int source_comments;
Local<Object> options = Local<Object>::Cast(args[0]); Local<Object> options = Local<Object>::Cast(optionsValue);
if (ctx_w) { if (ctx_w) {
NanInitPersistent(Object, stats, Local<Object>::Cast(options->Get(NanSymbol("stats"))));
// async (callback) style // async (callback) style
Local<Function> callback = Local<Function>::Cast(options->Get(NanSymbol("success"))); Local<Function> callback = Local<Function>::Cast(options->Get(NanSymbol("success")));
Local<Function> errorCallback = Local<Function>::Cast(options->Get(NanSymbol("error"))); Local<Function> errorCallback = Local<Function>::Cast(options->Get(NanSymbol("error")));
...@@ -41,13 +39,14 @@ void extractOptions(_NAN_METHOD_ARGS, void* cptr, sass_context_wrapper* ctx_w, b ...@@ -41,13 +39,14 @@ void extractOptions(_NAN_METHOD_ARGS, void* cptr, sass_context_wrapper* ctx_w, b
} else { } else {
ctx_w->ctx = (sass_context*) cptr; ctx_w->ctx = (sass_context*) cptr;
} }
ctx_w->stats = stats;
ctx_w->request.data = ctx_w; ctx_w->request.data = ctx_w;
ctx_w->callback = new NanCallback(callback); ctx_w->callback = new NanCallback(callback);
ctx_w->errorCallback = new NanCallback(errorCallback); ctx_w->errorCallback = new NanCallback(errorCallback);
} }
if (isFile) { if (isFile) {
sass_file_context *ctx = (sass_file_context*)cptr; sass_file_context* ctx = (sass_file_context*) cptr;
ctx->input_path = CreateString(options->Get(NanSymbol("file"))); ctx->input_path = CreateString(options->Get(NanSymbol("file")));
ctx->options.image_path = CreateString(options->Get(NanSymbol("imagePath"))); ctx->options.image_path = CreateString(options->Get(NanSymbol("imagePath")));
ctx->options.output_style = options->Get(NanSymbol("style"))->Int32Value(); ctx->options.output_style = options->Get(NanSymbol("style"))->Int32Value();
...@@ -57,7 +56,7 @@ void extractOptions(_NAN_METHOD_ARGS, void* cptr, sass_context_wrapper* ctx_w, b ...@@ -57,7 +56,7 @@ void extractOptions(_NAN_METHOD_ARGS, void* cptr, sass_context_wrapper* ctx_w, b
ctx->source_map_file = CreateString(options->Get(NanSymbol("sourceMap"))); ctx->source_map_file = CreateString(options->Get(NanSymbol("sourceMap")));
} }
} else { } else {
sass_context *ctx = (sass_context*)cptr; sass_context* ctx = (sass_context*) cptr;
ctx->source_string = CreateString(options->Get(NanSymbol("data"))); ctx->source_string = CreateString(options->Get(NanSymbol("data")));
ctx->options.image_path = CreateString(options->Get(NanSymbol("imagePath"))); ctx->options.image_path = CreateString(options->Get(NanSymbol("imagePath")));
ctx->options.output_style = options->Get(NanSymbol("style"))->Int32Value(); ctx->options.output_style = options->Get(NanSymbol("style"))->Int32Value();
...@@ -66,14 +65,44 @@ void extractOptions(_NAN_METHOD_ARGS, void* cptr, sass_context_wrapper* ctx_w, b ...@@ -66,14 +65,44 @@ void extractOptions(_NAN_METHOD_ARGS, void* cptr, sass_context_wrapper* ctx_w, b
} }
} }
template<typename Ctx>
void FillStatsObj(Handle<Object> stats, Ctx ctx) {
int i;
Handle<Array> arr;
arr = Array::New(ctx->num_included_files);
for (i = 0; i < ctx->num_included_files; i++) {
arr->Set(i, String::New(ctx->included_files[i]));
}
(*stats)->Set(NanSymbol("includedFiles"), arr);
}
void FillStatsObj(Handle<Object> stats, sass_file_context* ctx) {
Handle<Value> source_map;
FillStatsObj<sass_file_context*>(stats, ctx);
if (ctx->options.source_comments == SASS_SOURCE_COMMENTS_MAP) {
source_map = String::New(ctx->source_map_string);
} else {
source_map = Null();
}
(*stats)->Set(NanSymbol("sourceMap"), source_map);
}
void MakeCallback(uv_work_t* req) { void MakeCallback(uv_work_t* req) {
NanScope(); NanScope();
TryCatch try_catch; TryCatch try_catch;
sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data); sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data);
Handle<Value> val, err; Handle<Value> val, err;
const unsigned argc = 2;
int error_status = ctx_w->ctx ? ctx_w->ctx->error_status : ctx_w->fctx->error_status; int error_status = ctx_w->ctx ? ctx_w->ctx->error_status : ctx_w->fctx->error_status;
if (ctx_w->ctx) {
FillStatsObj(ctx_w->stats, ctx_w->ctx);
} else {
FillStatsObj(ctx_w->stats, ctx_w->fctx);
}
if (error_status == 0) { if (error_status == 0) {
// if no error, do callback(null, result) // if no error, do callback(null, result)
Handle<Value> source_map; Handle<Value> source_map;
...@@ -84,28 +113,23 @@ void MakeCallback(uv_work_t* req) { ...@@ -84,28 +113,23 @@ void MakeCallback(uv_work_t* req) {
} }
val = ctx_w->ctx ? NanNewLocal(String::New(ctx_w->ctx->output_string)) : NanNewLocal(String::New(ctx_w->fctx->output_string)); val = ctx_w->ctx ? NanNewLocal(String::New(ctx_w->ctx->output_string)) : NanNewLocal(String::New(ctx_w->fctx->output_string));
Local<Value> argv[argc] = { Local<Value> argv[] = {
NanNewLocal(val), NanNewLocal(val),
NanNewLocal(source_map), NanNewLocal(source_map)
}; };
ctx_w->callback->Call(argc, argv); ctx_w->callback->Call(2, argv);
} else { } else {
// if error, do callback(error) // if error, do callback(error)
err = ctx_w->ctx ? NanNewLocal(String::New(ctx_w->ctx->error_message)) : NanNewLocal(String::New(ctx_w->fctx->error_message)); err = ctx_w->ctx ? NanNewLocal(String::New(ctx_w->ctx->error_message)) : NanNewLocal(String::New(ctx_w->fctx->error_message));
Local<Value> argv[argc] = { Local<Value> argv[] = {
NanNewLocal(err), NanNewLocal(err),
NanNewLocal(Integer::New(error_status)) NanNewLocal(Integer::New(error_status))
}; };
ctx_w->errorCallback->Call(argc, argv); ctx_w->errorCallback->Call(2, argv);
} }
if (try_catch.HasCaught()) { if (try_catch.HasCaught()) {
node::FatalException(try_catch); node::FatalException(try_catch);
} }
if (ctx_w->ctx) {
delete ctx_w->ctx->source_string;
} else {
delete ctx_w->fctx->input_path;
}
sass_free_context_wrapper(ctx_w); sass_free_context_wrapper(ctx_w);
} }
...@@ -115,7 +139,7 @@ NAN_METHOD(Render) { ...@@ -115,7 +139,7 @@ NAN_METHOD(Render) {
sass_context* ctx = sass_new_context(); sass_context* ctx = sass_new_context();
sass_context_wrapper* ctx_w = sass_new_context_wrapper(); sass_context_wrapper* ctx_w = sass_new_context_wrapper();
ctx_w->ctx = ctx; ctx_w->ctx = ctx;
extractOptions(args, ctx, ctx_w, false); ExtractOptions(args[0], ctx, ctx_w, false);
int status = uv_queue_work(uv_default_loop(), &ctx_w->request, WorkOnContext, (uv_after_work_cb)MakeCallback); int status = uv_queue_work(uv_default_loop(), &ctx_w->request, WorkOnContext, (uv_after_work_cb)MakeCallback);
assert(status == 0); assert(status == 0);
...@@ -125,25 +149,22 @@ NAN_METHOD(Render) { ...@@ -125,25 +149,22 @@ NAN_METHOD(Render) {
NAN_METHOD(RenderSync) { NAN_METHOD(RenderSync) {
NanScope(); NanScope();
Handle<Object> options = args[0]->ToObject();
sass_context* ctx = sass_new_context(); sass_context* ctx = sass_new_context();
extractOptions(args, ctx, NULL, false); ExtractOptions(args[0], ctx, NULL, false);
sass_compile(ctx); sass_compile(ctx);
delete ctx->source_string; FillStatsObj(options->Get(NanSymbol("stats"))->ToObject(), ctx);
ctx->source_string = NULL;
delete ctx->options.include_paths;
ctx->options.include_paths = NULL;
if (ctx->error_status == 0) { if (ctx->error_status == 0) {
Local<Value> output = NanNewLocal(String::New(ctx->output_string)); Local<Value> output = NanNewLocal(String::New(ctx->output_string));
sass_free_context(ctx); free_context(ctx);
NanReturnValue(output); NanReturnValue(output);
} }
Local<String> error = String::New(ctx->error_message); Local<String> error = String::New(ctx->error_message);
free_context(ctx);
sass_free_context(ctx);
NanThrowError(error); NanThrowError(error);
NanReturnUndefined(); NanReturnUndefined();
} }
...@@ -153,7 +174,7 @@ NAN_METHOD(RenderFile) { ...@@ -153,7 +174,7 @@ NAN_METHOD(RenderFile) {
sass_file_context* fctx = sass_new_file_context(); sass_file_context* fctx = sass_new_file_context();
sass_context_wrapper* ctx_w = sass_new_context_wrapper(); sass_context_wrapper* ctx_w = sass_new_context_wrapper();
ctx_w->fctx = fctx; ctx_w->fctx = fctx;
extractOptions(args, fctx, ctx_w, true); ExtractOptions(args[0], fctx, ctx_w, true);
int status = uv_queue_work(uv_default_loop(), &ctx_w->request, WorkOnContext, (uv_after_work_cb)MakeCallback); int status = uv_queue_work(uv_default_loop(), &ctx_w->request, WorkOnContext, (uv_after_work_cb)MakeCallback);
assert(status == 0); assert(status == 0);
...@@ -164,24 +185,21 @@ NAN_METHOD(RenderFile) { ...@@ -164,24 +185,21 @@ NAN_METHOD(RenderFile) {
NAN_METHOD(RenderFileSync) { NAN_METHOD(RenderFileSync) {
NanScope(); NanScope();
sass_file_context* ctx = sass_new_file_context(); sass_file_context* ctx = sass_new_file_context();
extractOptions(args, ctx, NULL, true); ExtractOptions(args[0], ctx, NULL, true);
Handle<Object> options = args[0]->ToObject();
sass_compile_file(ctx); sass_compile_file(ctx);
delete ctx->input_path; FillStatsObj(options->Get(NanSymbol("stats"))->ToObject(), ctx);
ctx->input_path = NULL;
delete ctx->options.include_paths;
ctx->options.include_paths = NULL;
if (ctx->error_status == 0) { if (ctx->error_status == 0) {
Local<Value> output = NanNewLocal(String::New(ctx->output_string)); Local<Value> output = NanNewLocal(String::New(ctx->output_string));
sass_free_file_context(ctx); free_file_context(ctx);
NanReturnValue(output); NanReturnValue(output);
} }
Local<String> error = String::New(ctx->error_message);
sass_free_file_context(ctx);
Local<String> error = String::New(ctx->error_message);
free_file_context(ctx);
NanThrowError(error); NanThrowError(error);
NanReturnUndefined(); NanReturnUndefined();
} }
......
...@@ -3,14 +3,14 @@ var fs = require('fs'); ...@@ -3,14 +3,14 @@ var fs = require('fs');
function requireBinding() { function requireBinding() {
var v8 = 'v8-' + /[0-9]+\.[0-9]+/.exec(process.versions.v8)[0]; var v8 = 'v8-' + /[0-9]+\.[0-9]+/.exec(process.versions.v8)[0];
var candidates = [ var candidates = [
[__dirname, 'build', 'Release', 'obj.target', 'binding.node'], [__dirname, 'build', 'Release', 'obj.target', 'binding.node'],
[__dirname, 'bin', process.platform + '-' + process.arch + '-' + v8, 'binding.node'], [__dirname, 'bin', process.platform + '-' + process.arch + '-' + v8, 'binding.node']
]; ];
var candidate;
for (var i = 0, l = candidates.length; i < l; i++) { for (var i = 0, l = candidates.length; i < l; i++) {
var candidate = path.join.apply(path.join, candidates[i]); candidate = path.join.apply(path.join, candidates[i]);
if (fs.existsSync(candidate)) { if (fs.existsSync(candidate)) {
return require(candidate); return require(candidate);
...@@ -27,25 +27,31 @@ var SASS_OUTPUT_STYLE = { ...@@ -27,25 +27,31 @@ var SASS_OUTPUT_STYLE = {
expanded: 1, expanded: 1,
compact: 2, compact: 2,
compressed: 3 compressed: 3
}; };
var SASS_SOURCE_COMMENTS = { var SASS_SOURCE_COMMENTS = {
none: 0, none: 0,
normal: 1, normal: 1,
'default': 1, 'default': 1,
map: 2 map: 2
}; };
var noop = function () {};
var prepareOptions = function (options) { var prepareOptions = function (options) {
var success;
var error;
var stats;
var sourceComments; var sourceComments;
options = options || {}; options = options || {};
success = options.success;
error = options.error;
stats = options.stats || {};
sourceComments = options.source_comments || options.sourceComments; sourceComments = options.source_comments || options.sourceComments;
if (options.sourceMap && !sourceComments) { if (options.sourceMap && !sourceComments) {
sourceComments = 'map'; sourceComments = 'map';
} }
prepareStats(options, stats);
return { return {
file: options.file || null, file: options.file || null,
...@@ -55,12 +61,33 @@ var prepareOptions = function (options) { ...@@ -55,12 +61,33 @@ var prepareOptions = function (options) {
imagePath: options.image_path || options.imagePath || '', imagePath: options.image_path || options.imagePath || '',
style: SASS_OUTPUT_STYLE[options.output_style || options.outputStyle] || 0, style: SASS_OUTPUT_STYLE[options.output_style || options.outputStyle] || 0,
comments: SASS_SOURCE_COMMENTS[sourceComments] || 0, comments: SASS_SOURCE_COMMENTS[sourceComments] || 0,
stats: stats,
sourceMap: options.sourceMap, sourceMap: options.sourceMap,
success: options.success || noop, success: function onSuccess(css, sourceMap) {
error: options.error || noop finishStats(stats, sourceMap);
success && success(css, sourceMap);
},
error: function onError(err, errStatus) {
error && error(err, errStatus);
}
}; };
}; };
var prepareStats = function (options, stats) {
stats.entry = options.file || 'data';
stats.start = Date.now();
return stats;
};
var finishStats = function (stats, sourceMap) {
stats.end = Date.now();
stats.duration = stats.end - stats.start;
stats.sourceMap = sourceMap;
return stats;
};
var deprecatedRender = function(css, callback, options) { var deprecatedRender = function(css, callback, options) {
options = prepareOptions(options); options = prepareOptions(options);
// providing the deprecated single callback signature // providing the deprecated single callback signature
...@@ -68,12 +95,14 @@ var deprecatedRender = function(css, callback, options) { ...@@ -68,12 +95,14 @@ var deprecatedRender = function(css, callback, options) {
options.success = function(css) { options.success = function(css) {
callback(null, css); callback(null, css);
}; };
return binding.render(css, options.imagePath, options.success, options.error, options.paths, options.style, options.comments); options.data = css;
binding.render(options);
}; };
var deprecatedRenderSync = function(css, options) { var deprecatedRenderSync = function(css, options) {
options = prepareOptions(options); options = prepareOptions(options);
return binding.renderSync(css, options.imagePath, options.paths, options.style, options.comments); options.data = css;
return binding.renderSync(options);
}; };
exports.render = function(options) { exports.render = function(options) {
...@@ -82,28 +111,21 @@ exports.render = function(options) { ...@@ -82,28 +111,21 @@ exports.render = function(options) {
} }
options = prepareOptions(options); options = prepareOptions(options);
options.file? binding.renderFile(options) : binding.render(options);
if (options.file) {
return binding.renderFile(options.file, options.imagePath, options.success, options.error, options.paths, options.style, options.comments, options.sourceMap);
}
//Assume data is present if file is not. binding/libsass will tell the user otherwise!
return binding.render(options.data, options.imagePath, options.success, options.error, options.paths, options.style);
}; };
exports.renderSync = function(options) { exports.renderSync = function(options) {
var output;
if (typeof arguments[0] === 'string') { if (typeof arguments[0] === 'string') {
return deprecatedRenderSync.apply(this, arguments); return deprecatedRenderSync.apply(this, arguments);
} }
options = prepareOptions(options); options = prepareOptions(options);
output = options.file? binding.renderFileSync(options) : binding.renderSync(options);
finishStats(options.stats);
if (options.file) { return output;
return binding.renderFileSync(options.file, options.imagePath, options.paths, options.style, options.comments);
}
//Assume data is present if file is not. binding/libsass will tell the user otherwise!
return binding.renderSync(options.data, options.imagePath, options.paths, options.style);
}; };
/** /**
......
#include "sass_context_wrapper.h" #include "sass_context_wrapper.h"
#include <nan.h>
#include <cstdlib> #include <cstdlib>
extern "C" { extern "C" {
using namespace std; using namespace std;
sass_context_wrapper* sass_new_context_wrapper() void free_context(sass_context* ctx) {
{ delete[] ctx->source_string;
delete[] ctx->options.include_paths;
delete[] ctx->options.image_path;
sass_free_context(ctx);
}
void free_file_context(sass_file_context* fctx) {
delete[] fctx->input_path;
delete[] fctx->output_path;
delete[] fctx->options.include_paths;
delete[] fctx->options.image_path;
sass_free_file_context(fctx);
}
sass_context_wrapper* sass_new_context_wrapper() {
return (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper)); return (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper));
} }
void sass_free_context_wrapper(sass_context_wrapper* ctx_w) void sass_free_context_wrapper(sass_context_wrapper* ctx_w) {
{ if (ctx_w->ctx) {
if (ctx_w->ctx) sass_free_context(ctx_w->ctx); free_context(ctx_w->ctx);
if (ctx_w->fctx) sass_free_file_context(ctx_w->fctx); } else if (ctx_w->fctx) {
free_file_context(ctx_w->fctx);
}
NanDisposePersistent(ctx_w->stats);
delete ctx_w->callback; delete ctx_w->callback;
delete ctx_w->errorCallback; delete ctx_w->errorCallback;
......
...@@ -5,9 +5,15 @@ ...@@ -5,9 +5,15 @@
extern "C" { extern "C" {
#endif #endif
using namespace v8;
void free_context(sass_context* ctx);
void free_file_context(sass_file_context* fctx);
struct sass_context_wrapper { struct sass_context_wrapper {
sass_context* ctx; sass_context* ctx;
sass_file_context* fctx; sass_file_context* fctx;
Persistent<Object> stats;
uv_work_t request; uv_work_t request;
NanCallback* callback; NanCallback* callback;
NanCallback* errorCallback; NanCallback* errorCallback;
......
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