Skip to content
This repository has been archived by the owner on Jul 24, 2024. It is now read-only.

Implement sass value operations and stringification #1478

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions src/sass_types/sass_value_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ namespace SassTypes
static v8::Local<v8::Function> get_constructor();
static v8::Local<v8::FunctionTemplate> get_constructor_template();
static NAN_METHOD(New);
static NAN_METHOD(Stringify);
static NAN_METHOD(Operation);
static Sass_Value *fail(const char *, Sass_Value **);

protected:
Expand Down Expand Up @@ -73,6 +75,8 @@ namespace SassTypes
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New<v8::String>(T::get_constructor_name()).ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Nan::SetPrototypeMethod(tpl, "operation", Operation);
Nan::SetPrototypeMethod(tpl, "toString", Stringify);
T::initPrototype(tpl);

return scope.Escape(tpl);
Expand All @@ -87,6 +91,65 @@ namespace SassTypes
return Nan::New(constructor);
}

template <class T>
NAN_METHOD(SassValueWrapper<T>::Operation) {
if (info.Length() < 2) {
return Nan::ThrowTypeError("Not enough arguments for operation");
}
if (!info[0]->IsString()) {
return Nan::ThrowTypeError("Operation value should be a string");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried to stay as close as possible to other error messages.
But I just couldn't help wondering, why should and not must?
To me it looks like a very strict constraint one should meet 😉

}
if (SassTypes::Value *rhs = SassTypes::Factory::unwrap(info[1])) {
Copy link
Contributor Author

@mgreter mgreter Apr 24, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unwrap doesn't seem to upgrade native type automatically?
I would have wished for it to handle i.e. native numbers transparently for me.
It would automatically allow stuff like val.operation("mul", 2);
I use that for returns in custom function too (is that possible in node-sass)?
Looking at the code it seem "A SassValue object was expected." ...
Or is there another utility function that does just that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unwrap generates whatever it can, currently only non-native artificial SassTypes. #1310 is there to introduce proper primitive JavaScript null, I have also a patch to introduce native true and false.

Numbers are more difficult, since Sass number is actually a (number, unit) tuple and JavaScript does not support that.

// get and convert all needed input values
v8::String::Utf8Value op(info[0]->ToString());
Sass_OP operation = NUM_OPS; // abuse
Sass_Value* vlhs = unwrap(info.This())->value;
Sass_Value* vrhs = rhs->get_sass_value();
// hashing all cases for a switch is easy
// but only worth if performance is critical
if (strcmp("eq", *op)) { operation = EQ; }
else if (strcmp("gt", *op)) { operation = GT; }
else if (strcmp("lt", *op)) { operation = LT; }
else if (strcmp("or", *op)) { operation = OR; }
else if (strcmp("and", *op)) { operation = AND; }
else if (strcmp("neq", *op)) { operation = NEQ; }
else if (strcmp("gte", *op)) { operation = GTE; }
else if (strcmp("lte", *op)) { operation = LTE; }
else if (strcmp("add", *op)) { operation = ADD; }
else if (strcmp("sub", *op)) { operation = SUB; }
else if (strcmp("mul", *op)) { operation = MUL; }
else if (strcmp("div", *op)) { operation = DIV; }
else if (strcmp("mod", *op)) { operation = MOD; }
// check if we found a valid operation
if (operation != NUM_OPS) {
Sass_Value* result = sass_value_op(operation, vlhs, vrhs);
info.GetReturnValue().Set(Factory::create(result)->get_js_object());
sass_delete_value(result);
}
// free allocated resources
sass_delete_value(vlhs);
sass_delete_value(vrhs);
// last do error handling
if (operation == NUM_OPS) {
// throw only after all resources have been freed!
return Nan::ThrowTypeError("Operator not recognized");
}
} else {
// there was no valid right hand side
return Nan::ThrowTypeError("Operation has invalid right hand side");
}
}

template <class T>
NAN_METHOD(SassValueWrapper<T>::Stringify) {
union Sass_Value* result = sass_value_stringify(
unwrap(info.This())->value, false, 5);
const char* string = sass_string_get_value(result);
auto value = Nan::New<v8::String>(string).ToLocalChecked();
sass_delete_value(result); // free temporary value
info.GetReturnValue().Set(value);
}

template <class T>
NAN_METHOD(SassValueWrapper<T>::New) {
std::vector<v8::Local<v8::Value>> localArgs(info.Length());
Expand Down