summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnand Thakker <github@anandthakker.net>2017-07-06 09:37:59 -0400
committerAnand Thakker <github@anandthakker.net>2017-07-06 17:02:12 -0400
commit25c5c3bbb527509b4b840005510cbb0d85208b40 (patch)
tree2638b7602061d0172f3ae24bd90f311d40f74735
parent9db5832d362fb7f1930d4b182a3fe37af492a9a0 (diff)
downloadqtlocation-mapboxgl-25c5c3bbb527509b4b840005510cbb0d85208b40.tar.gz
Expose Expression in node and hook up integration test
-rw-r--r--cmake/node.cmake2
-rw-r--r--package.json2
-rw-r--r--platform/node/src/node_expression.cpp126
-rw-r--r--platform/node/src/node_expression.hpp36
-rw-r--r--platform/node/src/node_mapbox_gl_native.cpp2
-rw-r--r--platform/node/test/expression.test.js52
6 files changed, 219 insertions, 1 deletions
diff --git a/cmake/node.cmake b/cmake/node.cmake
index 502edd8293..add66e7fbb 100644
--- a/cmake/node.cmake
+++ b/cmake/node.cmake
@@ -21,6 +21,8 @@ target_sources(mbgl-node
PRIVATE platform/node/src/node_feature.cpp
PRIVATE platform/node/src/node_thread_pool.hpp
PRIVATE platform/node/src/node_thread_pool.cpp
+ PRIVATE platform/node/src/node_expression.hpp
+ PRIVATE platform/node/src/node_expression.cpp
PRIVATE platform/node/src/util/async_queue.hpp
)
diff --git a/package.json b/package.json
index e428a0db43..cdf09636c7 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"license": "BSD-2-Clause",
"dependencies": {
"node-pre-gyp": "^0.6.28",
- "nan": "^2.4.0"
+ "nan": "^2.6.2"
},
"devDependencies": {
"aws-sdk": "^2.3.5",
diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp
new file mode 100644
index 0000000000..51a9fca5ef
--- /dev/null
+++ b/platform/node/src/node_expression.cpp
@@ -0,0 +1,126 @@
+#include "node_expression.hpp"
+#include "node_conversion.hpp"
+
+#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/style/conversion/expression.hpp>
+#include <mbgl/util/geojson.hpp>
+#include <nan.h>
+
+using namespace mbgl::style;
+using namespace mbgl::style::expression;
+
+namespace node_mbgl {
+
+Nan::Persistent<v8::Function> NodeExpression::constructor;
+
+void NodeExpression::Init(v8::Local<v8::Object> target) {
+ v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
+ tpl->SetClassName(Nan::New("Expression").ToLocalChecked());
+ tpl->InstanceTemplate()->SetInternalFieldCount(1); // what is this doing?
+
+ Nan::SetPrototypeMethod(tpl, "evaluate", Evaluate);
+ Nan::SetPrototypeMethod(tpl, "getType", GetType);
+ Nan::SetPrototypeMethod(tpl, "isFeatureConstant", IsFeatureConstant);
+ Nan::SetPrototypeMethod(tpl, "isZoomConstant", IsZoomConstant);
+
+ constructor.Reset(tpl->GetFunction()); // what is this doing?
+ Nan::Set(target, Nan::New("Expression").ToLocalChecked(), tpl->GetFunction());
+}
+
+void NodeExpression::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ if (!info.IsConstructCall()) {
+ return Nan::ThrowTypeError("Use the new operator to create new Expression objects");
+ }
+
+ if (info.Length() < 1 || info[0]->IsUndefined()) {
+ return Nan::ThrowTypeError("Requires a JSON style expression argument.");
+ }
+
+ auto expr = info[0];
+
+ try {
+ conversion::Error error;
+ auto expression = conversion::convert<std::unique_ptr<Expression>>(expr, error);
+ if (!expression) {
+ return Nan::ThrowTypeError(error.message.c_str());
+ }
+ auto nodeExpr = new NodeExpression(std::move(*expression));
+ nodeExpr->Wrap(info.This());
+ } catch(std::exception &ex) {
+ return Nan::ThrowError(ex.what());
+ }
+
+ info.GetReturnValue().Set(info.This());
+}
+
+void NodeExpression::Evaluate(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ NodeExpression* nodeExpr = ObjectWrap::Unwrap<NodeExpression>(info.Holder());
+
+ if (info.Length() < 2) {
+ return Nan::ThrowTypeError("Requires arguments zoom and feature arguments.");
+ }
+
+ float zoom = info[0]->NumberValue();
+
+ // Pending https://github.com/mapbox/mapbox-gl-native/issues/5623,
+ // stringify the geojson feature in order to use convert<GeoJSON, string>()
+ Nan::JSON NanJSON;
+ Nan::MaybeLocal<v8::String> geojsonString = NanJSON.Stringify(Nan::To<v8::Object>(info[1]).ToLocalChecked());
+ if (geojsonString.IsEmpty()) {
+ return Nan::ThrowTypeError("couldn't stringify JSON");
+ }
+ conversion::Error conversionError;
+ mbgl::optional<mbgl::GeoJSON> geoJSON = conversion::convert<mbgl::GeoJSON, std::string>(*Nan::Utf8String(geojsonString.ToLocalChecked()), conversionError);
+ if (!geoJSON) {
+ Nan::ThrowTypeError(conversionError.message.c_str());
+ return;
+ }
+
+ try {
+ mapbox::geojson::feature feature = geoJSON->get<mapbox::geojson::feature>();
+ Error error;
+ auto result = nodeExpr->expression->evaluate(zoom, feature, error);
+ if (result) {
+ result->match(
+ [&] (const std::array<float, 2>&) {},
+ [&] (const std::array<float, 4>&) {},
+ [&] (const std::string s) {
+ info.GetReturnValue().Set(Nan::New(s.c_str()).ToLocalChecked());
+ },
+ [&] (const mbgl::Color& c) {
+ info.GetReturnValue().Set(Nan::New(c.stringify().c_str()).ToLocalChecked());
+ },
+ [&] (const auto& v) {
+ info.GetReturnValue().Set(Nan::New(v));
+ }
+ );
+ } else {
+ v8::Local<v8::Object> res = Nan::New<v8::Object>();
+ Nan::Set(res,
+ Nan::New("error").ToLocalChecked(),
+ Nan::New(error.message.c_str()).ToLocalChecked());
+ info.GetReturnValue().Set(res);
+ }
+ } catch(std::exception &ex) {
+ return Nan::ThrowTypeError(ex.what());
+ }
+}
+
+void NodeExpression::GetType(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ NodeExpression* nodeExpr = ObjectWrap::Unwrap<NodeExpression>(info.Holder());
+ const auto& type = nodeExpr->expression->getType();
+ const auto& name = type.match([&] (const auto& t) { return t.getName(); });
+ info.GetReturnValue().Set(Nan::New(name.c_str()).ToLocalChecked());
+}
+
+void NodeExpression::IsFeatureConstant(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ NodeExpression* nodeExpr = ObjectWrap::Unwrap<NodeExpression>(info.Holder());
+ info.GetReturnValue().Set(Nan::New(nodeExpr->expression->isFeatureConstant()));
+}
+
+void NodeExpression::IsZoomConstant(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ NodeExpression* nodeExpr = ObjectWrap::Unwrap<NodeExpression>(info.Holder());
+ info.GetReturnValue().Set(Nan::New(nodeExpr->expression->isZoomConstant()));
+}
+
+} // namespace node_mbgl
diff --git a/platform/node/src/node_expression.hpp b/platform/node/src/node_expression.hpp
new file mode 100644
index 0000000000..8913bead1b
--- /dev/null
+++ b/platform/node/src/node_expression.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <exception>
+#include <memory>
+#include <mbgl/style/function/expression.hpp>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wshadow"
+#include <nan.h>
+#pragma GCC diagnostic pop
+
+using namespace mbgl::style::expression;
+
+namespace node_mbgl {
+
+class NodeExpression : public Nan::ObjectWrap {
+public:
+ static void Init(v8::Local<v8::Object>);
+
+private:
+ NodeExpression(std::unique_ptr<Expression> expression_) :
+ expression(std::move(expression_))
+ {};
+
+ static void New(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void Evaluate(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void GetType(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void IsFeatureConstant(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void IsZoomConstant(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static Nan::Persistent<v8::Function> constructor;
+
+ std::unique_ptr<Expression> expression;
+};
+
+} // namespace node_mbgl
diff --git a/platform/node/src/node_mapbox_gl_native.cpp b/platform/node/src/node_mapbox_gl_native.cpp
index cdcc982220..96e96e4298 100644
--- a/platform/node/src/node_mapbox_gl_native.cpp
+++ b/platform/node/src/node_mapbox_gl_native.cpp
@@ -10,6 +10,7 @@
#include "node_map.hpp"
#include "node_logging.hpp"
#include "node_request.hpp"
+#include "node_expression.hpp"
void RegisterModule(v8::Local<v8::Object> target, v8::Local<v8::Object> module) {
// This has the effect of:
@@ -20,6 +21,7 @@ void RegisterModule(v8::Local<v8::Object> target, v8::Local<v8::Object> module)
node_mbgl::NodeMap::Init(target);
node_mbgl::NodeRequest::Init();
+ node_mbgl::NodeExpression::Init(target);
// Exports Resource constants.
v8::Local<v8::Object> resource = Nan::New<v8::Object>();
diff --git a/platform/node/test/expression.test.js b/platform/node/test/expression.test.js
new file mode 100644
index 0000000000..c243ba1e0e
--- /dev/null
+++ b/platform/node/test/expression.test.js
@@ -0,0 +1,52 @@
+'use strict';
+
+var suite = require('../../../mapbox-gl-js/test/integration').expression;
+var mbgl = require('../index');
+
+var tests;
+
+if (process.argv[1] === __filename && process.argv.length > 2) {
+ tests = process.argv.slice(2);
+}
+
+suite.run('native', {tests: tests}, (fixture) => {
+ const compileResult = {};
+ const testResult = {
+ compileResult
+ };
+
+ try {
+ const expression = new mbgl.Expression(fixture.expression);
+ compileResult.result = 'success';
+ compileResult.isFeatureConstant = expression.isFeatureConstant();
+ compileResult.isZoomConstant = expression.isZoomConstant();
+ compileResult.type = expression.getType();
+
+ if (fixture.evaluate) {
+ const evaluateResults = [];
+ for (const input of fixture.evaluate) {
+ const zoom = typeof input[0].zoom === 'number' ?
+ input[0].zoom : -1;
+
+ const feature = Object.assign({
+ type: 'Feature',
+ properties: {},
+ geometry: { type: 'Unknown', coordinates: [] }
+ }, input[1])
+
+ const output = expression.evaluate(zoom, feature);
+ evaluateResults.push(output);
+ }
+
+ if (evaluateResults.length) {
+ testResult.evaluateResults = evaluateResults;
+ }
+ }
+ } catch (e) {
+ compileResult.result = 'error';
+ compileResult.errors = [e.message];
+ }
+
+ return testResult;
+});
+