From 18dcd27a9be154a82e06832c48951b5463a497a6 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Wed, 16 Nov 2022 15:44:36 +0100 Subject: [PATCH] Use node-api instead of NAN (#6452) --- .github/workflows/osrm-backend.yml | 144 +--- .gitignore | 1 + CHANGELOG.md | 2 + include/nodejs/json_v8_renderer.hpp | 44 +- include/nodejs/node_osrm.hpp | 41 +- include/nodejs/node_osrm_support.hpp | 996 +++++++++++++-------------- lib/binding_napi_v8 | 1 + package-lock.json | 139 ++-- package.json | 15 +- src/nodejs/CMakeLists.txt | 12 + src/nodejs/node_osrm.cpp | 170 +++-- test/nodejs/benchmark.js | 51 ++ test/nodejs/index.js | 2 +- 13 files changed, 785 insertions(+), 833 deletions(-) create mode 120000 lib/binding_napi_v8 create mode 100644 test/nodejs/benchmark.js diff --git a/.github/workflows/osrm-backend.yml b/.github/workflows/osrm-backend.yml index 4edcaf771..53a27b864 100644 --- a/.github/workflows/osrm-backend.yml +++ b/.github/workflows/osrm-backend.yml @@ -20,7 +20,7 @@ env: ENABLE_NODE_BINDINGS: "ON" jobs: - windows: + windows-release-node: needs: format-taginfo-docs runs-on: windows-2022 continue-on-error: false @@ -264,83 +264,7 @@ jobs: CXXCOMPILER: g++-8 CXXFLAGS: -Wno-cast-function-type - - name: conan-macos-x64-release-node-16 - build_node_package: true - continue-on-error: false - node: 16 - runs-on: macos-11 - BUILD_TOOLS: ON - BUILD_TYPE: Release - CCOMPILER: clang - CXXCOMPILER: clang++ - CUCUMBER_TIMEOUT: 60000 - ENABLE_ASSERTIONS: ON - ENABLE_CONAN: ON - - - name: conan-macos-arm64-release-node-16 - build_node_package: true - continue-on-error: false - node: 16 - runs-on: macos-11 - BUILD_TOOLS: ON - BUILD_TYPE: Release - CCOMPILER: clang - CXXCOMPILER: clang++ - CUCUMBER_TIMEOUT: 60000 - ENABLE_ASSERTIONS: ON - ENABLE_CONAN: ON - ENABLE_APPLE_SILICON: ON - - - name: conan-macos-x64-release-node-18 - build_node_package: true - continue-on-error: false - node: 18 - runs-on: macos-11 - BUILD_TOOLS: ON - BUILD_TYPE: Release - CCOMPILER: clang - CXXCOMPILER: clang++ - CUCUMBER_TIMEOUT: 60000 - ENABLE_ASSERTIONS: ON - ENABLE_CONAN: ON - - - name: conan-macos-arm64-release-node-18 - build_node_package: true - continue-on-error: false - node: 18 - runs-on: macos-11 - BUILD_TOOLS: ON - BUILD_TYPE: Release - CCOMPILER: clang - CXXCOMPILER: clang++ - CUCUMBER_TIMEOUT: 60000 - ENABLE_ASSERTIONS: ON - ENABLE_CONAN: ON - ENABLE_APPLE_SILICON: ON - - - name: node-16-conan-linux-release - build_node_package: true - continue-on-error: false - node: 16 - runs-on: ubuntu-20.04 - BUILD_TYPE: Release - CCOMPILER: clang-6.0 - CXXCOMPILER: clang++-6.0 - ENABLE_CONAN: ON - NODE_PACKAGE_TESTS_ONLY: ON - - - name: node-16-conan-linux-debug - build_node_package: true - continue-on-error: false - node: 16 - runs-on: ubuntu-20.04 - BUILD_TYPE: Debug - CCOMPILER: clang-6.0 - CXXCOMPILER: clang++-6.0 - ENABLE_CONAN: ON - NODE_PACKAGE_TESTS_ONLY: ON - - - name: node-18-conan-linux-release + - name: conan-linux-release-node build_node_package: true continue-on-error: false node: 18 @@ -351,7 +275,7 @@ jobs: ENABLE_CONAN: ON NODE_PACKAGE_TESTS_ONLY: ON - - name: node-18-conan-linux-debug + - name: conan-linux-debug-node build_node_package: true continue-on-error: false node: 18 @@ -362,10 +286,10 @@ jobs: ENABLE_CONAN: ON NODE_PACKAGE_TESTS_ONLY: ON - - name: conan-macos-x64-release-node-latest + - name: conan-macos-x64-release-node build_node_package: true continue-on-error: true - node: latest + node: 18 runs-on: macos-11 BUILD_TYPE: Release CCOMPILER: clang @@ -374,10 +298,10 @@ jobs: ENABLE_ASSERTIONS: ON ENABLE_CONAN: ON - - name: conan-macos-arm64-release-node-latest + - name: conan-macos-arm64-release-node build_node_package: true continue-on-error: true - node: latest + node: 18 runs-on: macos-11 BUILD_TYPE: Release CCOMPILER: clang @@ -387,28 +311,6 @@ jobs: ENABLE_CONAN: ON ENABLE_APPLE_SILICON: ON - - name: node-latest-conan-linux-release - build_node_package: true - continue-on-error: true - node: latest - runs-on: ubuntu-20.04 - BUILD_TYPE: Release - CCOMPILER: clang-6.0 - CXXCOMPILER: clang++-6.0 - ENABLE_CONAN: ON - NODE_PACKAGE_TESTS_ONLY: ON - - - name: node-latest-conan-linux-debug - build_node_package: true - continue-on-error: true - node: latest - runs-on: ubuntu-20.04 - BUILD_TYPE: Debug - CCOMPILER: clang-6.0 - CXXCOMPILER: clang++-6.0 - ENABLE_CONAN: ON - NODE_PACKAGE_TESTS_ONLY: ON - name: ${{ matrix.name}} continue-on-error: ${{ matrix.continue-on-error }} runs-on: ${{ matrix.runs-on }} @@ -627,10 +529,38 @@ jobs: ./src/benchmarks/packedvector-bench ./src/benchmarks/rtree-bench ../test/data/monaco.osrm.ramIndex ../test/data/monaco.osrm.fileIndex ../test/data/monaco.osrm.nbg_nodes popd - - name: Run Node package tests only + + - name: Use Node 16 + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' && matrix.ENABLE_APPLE_SILICON != 'ON' }} + uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Run Node package tests on Node 16 if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' && matrix.ENABLE_APPLE_SILICON != 'ON' }} run: | + node --version npm run nodejs-tests + - name: Use Node 18 + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' && matrix.ENABLE_APPLE_SILICON != 'ON' }} + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Run Node package tests on Node 18 + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' && matrix.ENABLE_APPLE_SILICON != 'ON' }} + run: | + node --version + npm run nodejs-tests + - name: Use Node latest + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' && matrix.ENABLE_APPLE_SILICON != 'ON' }} + uses: actions/setup-node@v3 + with: + node-version: latest + - name: Run Node package tests on Node-latest + if: ${{ matrix.NODE_PACKAGE_TESTS_ONLY == 'ON' && matrix.ENABLE_APPLE_SILICON != 'ON' }} + run: | + node --version + npm run nodejs-tests + - name: Upload test logs uses: actions/upload-artifact@v3 if: failure() @@ -681,6 +611,6 @@ jobs: ci-complete: runs-on: ubuntu-22.04 - needs: [build-test-publish, docker-image, windows] + needs: [build-test-publish, docker-image, windows-release-node] steps: - run: echo "CI complete" diff --git a/.gitignore b/.gitignore index 3b443d06d..9180d6fb5 100644 --- a/.gitignore +++ b/.gitignore @@ -105,3 +105,4 @@ debug.lua # node-osrm artifacts lib/binding + diff --git a/CHANGELOG.md b/CHANGELOG.md index 253cad5c2..9f39ab328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - CHANGED: Upgrade to clang-tidy 15. [#6439](https://github.com/Project-OSRM/osrm-backend/pull/6439) - CHANGED: Update actions/cache to v3. [#6420](https://github.com/Project-OSRM/osrm-backend/pull/6420) - REMOVED: Drop support of Node 12 & 14. [#6431](https://github.com/Project-OSRM/osrm-backend/pull/6431) + - NodeJS: + - CHANGED: Use node-api instead of NAN. [#6452](https://github.com/Project-OSRM/osrm-backend/pull/6452) - Misc: - REMOVED: Get rid of unused functions in util/json_util.hpp. [#6446](https://github.com/Project-OSRM/osrm-backend/pull/6446) - FIXED: Apply workaround for Conan installation issue on CI. [#6442](https://github.com/Project-OSRM/osrm-backend/pull/6442) diff --git a/include/nodejs/json_v8_renderer.hpp b/include/nodejs/json_v8_renderer.hpp index 7ff7e9382..4b8bbd193 100644 --- a/include/nodejs/json_v8_renderer.hpp +++ b/include/nodejs/json_v8_renderer.hpp @@ -2,11 +2,7 @@ #define OSRM_BINDINGS_NODE_JSON_V8_RENDERER_HPP #include "osrm/json_container.hpp" - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include -#pragma GCC diagnostic pop +#include #include @@ -15,52 +11,56 @@ namespace node_osrm struct V8Renderer { - explicit V8Renderer(v8::Local &_out) : out(_out) {} + explicit V8Renderer(const Napi::Env &env, Napi::Value &out) : env(env), out(out) {} void operator()(const osrm::json::String &string) const { - out = Nan::New(std::cref(string.value)).ToLocalChecked(); + out = Napi::String::New(env, string.value); } - void operator()(const osrm::json::Number &number) const { out = Nan::New(number.value); } + void operator()(const osrm::json::Number &number) const + { + out = Napi::Number::New(env, number.value); + } void operator()(const osrm::json::Object &object) const { - v8::Local obj = Nan::New(); + Napi::Object obj = Napi::Object::New(env); for (const auto &keyValue : object.values) { - v8::Local child; - mapbox::util::apply_visitor(V8Renderer(child), keyValue.second); - Nan::Set(obj, Nan::New(keyValue.first).ToLocalChecked(), child); + Napi::Value child; + mapbox::util::apply_visitor(V8Renderer(env, child), keyValue.second); + obj.Set(keyValue.first, child); } out = obj; } void operator()(const osrm::json::Array &array) const { - v8::Local a = Nan::New(array.values.size()); + Napi::Array a = Napi::Array::New(env, array.values.size()); for (auto i = 0u; i < array.values.size(); ++i) { - v8::Local child; - mapbox::util::apply_visitor(V8Renderer(child), array.values[i]); - Nan::Set(a, i, child); + Napi::Value child; + mapbox::util::apply_visitor(V8Renderer(env, child), array.values[i]); + a.Set(i, child); } out = a; } - void operator()(const osrm::json::True &) const { out = Nan::New(true); } + void operator()(const osrm::json::True &) const { out = Napi::Boolean::New(env, true); } - void operator()(const osrm::json::False &) const { out = Nan::New(false); } + void operator()(const osrm::json::False &) const { out = Napi::Boolean::New(env, false); } - void operator()(const osrm::json::Null &) const { out = Nan::Null(); } + void operator()(const osrm::json::Null &) const { out = env.Null(); } private: - v8::Local &out; + const Napi::Env &env; + Napi::Value &out; }; -inline void renderToV8(v8::Local &out, const osrm::json::Object &object) +inline void renderToV8(const Napi::Env &env, Napi::Value &out, const osrm::json::Object &object) { - V8Renderer renderer(out); + V8Renderer renderer(env, out); renderer(object); } } // namespace node_osrm diff --git a/include/nodejs/node_osrm.hpp b/include/nodejs/node_osrm.hpp index c9f09e75b..f85fb5362 100644 --- a/include/nodejs/node_osrm.hpp +++ b/include/nodejs/node_osrm.hpp @@ -3,45 +3,30 @@ #include "osrm/osrm_fwd.hpp" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include -#pragma GCC diagnostic pop +#include #include namespace node_osrm { -struct Engine final : public Nan::ObjectWrap +class Engine final : public Napi::ObjectWrap { - using Base = Nan::ObjectWrap; + public: + static Napi::Object Init(Napi::Env env, Napi::Object exports); + Engine(const Napi::CallbackInfo &info); - static NAN_MODULE_INIT(Init); - - static NAN_METHOD(New); - - static NAN_METHOD(route); - static NAN_METHOD(nearest); - static NAN_METHOD(table); - static NAN_METHOD(tile); - static NAN_METHOD(match); - static NAN_METHOD(trip); - - Engine(osrm::EngineConfig &config); - - // Thread-safe singleton accessor - static Nan::Persistent &constructor(); - - // Ref-counted OSRM alive even after shutdown until last callback is done std::shared_ptr this_; + + private: + Napi::Value route(const Napi::CallbackInfo &info); + Napi::Value nearest(const Napi::CallbackInfo &info); + Napi::Value table(const Napi::CallbackInfo &info); + Napi::Value tile(const Napi::CallbackInfo &info); + Napi::Value match(const Napi::CallbackInfo &info); + Napi::Value trip(const Napi::CallbackInfo &info); }; } // namespace node_osrm -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -NAN_MODULE_WORKER_ENABLED(osrm, node_osrm::Engine::Init) -#pragma GCC diagnostic pop - #endif diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index 2faaa32f6..a1d7b4473 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -18,6 +18,7 @@ #include "osrm/tile_parameters.hpp" #include "osrm/trip_parameters.hpp" #include "util/json_renderer.hpp" +#include #include #include @@ -52,30 +53,40 @@ struct PluginParameters using ObjectOrString = typename mapbox::util::variant; -template inline v8::Local render(const ResultT &result); +template inline Napi::Value render(const Napi::Env &env, const ResultT &result); -template <> v8::Local inline render(const std::string &result) +template <> Napi::Value inline render(const Napi::Env &env, const std::string &result) { - return Nan::CopyBuffer(result.data(), result.size()).ToLocalChecked(); + return Napi::Buffer::Copy(env, result.data(), result.size()); } -template <> v8::Local inline render(const ObjectOrString &result) +template <> Napi::Value inline render(const Napi::Env &env, const ObjectOrString &result) { if (result.is()) { // Convert osrm::json object tree into matching v8 object tree - v8::Local value; - renderToV8(value, result.get()); + Napi::Value value; + renderToV8(env, value, result.get()); return value; } else { // Return the string object as a node Buffer - return Nan::CopyBuffer(result.get().data(), result.get().size()) - .ToLocalChecked(); + return Napi::Buffer::Copy( + env, result.get().data(), result.get().size()); } } +inline bool IsUnsignedInteger(const Napi::Value &value) +{ + if (!value.IsNumber()) + { + return false; + } + const auto doubleValue = value.ToNumber().DoubleValue(); + return doubleValue >= 0.0 && std::floor(doubleValue) == doubleValue; +} + inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result) { const auto code_iter = result.values.find("code"); @@ -109,9 +120,19 @@ inline void ParseResult(const osrm::Status &result_status, } } -inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo &args) +inline void ThrowError(const Napi::Env &env, const char *message) { - Nan::HandleScope scope; + Napi::Error::New(env, message).ThrowAsJavaScriptException(); +} + +inline void ThrowTypeError(const Napi::Env &env, const char *message) +{ + Napi::TypeError::New(env, message).ThrowAsJavaScriptException(); +} + +inline engine_config_ptr argumentsToEngineConfig(const Napi::CallbackInfo &args) +{ + Napi::HandleScope scope(args.Env()); auto engine_config = std::make_unique(); if (args.Length() == 0) @@ -120,261 +141,250 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo } else if (args.Length() > 1) { - Nan::ThrowError("Only accepts one parameter"); + ThrowError(args.Env(), "Only accepts one parameter"); return engine_config_ptr(); } BOOST_ASSERT(args.Length() == 1); - if (args[0]->IsString()) + if (args[0].IsString()) { - engine_config->storage_config = - osrm::StorageConfig(*Nan::Utf8String(Nan::To(args[0]).ToLocalChecked())); + engine_config->storage_config = osrm::StorageConfig(args[0].ToString().Utf8Value()); engine_config->use_shared_memory = false; return engine_config; } - else if (!args[0]->IsObject()) + else if (!args[0].IsObject()) { - Nan::ThrowError("Parameter must be a path or options object"); + ThrowError(args.Env(), "Parameter must be a path or options object"); return engine_config_ptr(); } - BOOST_ASSERT(args[0]->IsObject()); - auto params = Nan::To(args[0]).ToLocalChecked(); + BOOST_ASSERT(args[0].IsObject()); + auto params = args[0].As(); - auto path = Nan::Get(params, Nan::New("path").ToLocalChecked()).ToLocalChecked(); + auto path = params.Get("path"); if (path.IsEmpty()) return engine_config_ptr(); - auto memory_file = Nan::Get(params, Nan::New("memory_file").ToLocalChecked()).ToLocalChecked(); + auto memory_file = params.Get("memory_file"); if (memory_file.IsEmpty()) return engine_config_ptr(); - auto shared_memory = - Nan::Get(params, Nan::New("shared_memory").ToLocalChecked()).ToLocalChecked(); + auto shared_memory = params.Get("shared_memory"); if (shared_memory.IsEmpty()) return engine_config_ptr(); - auto mmap_memory = Nan::Get(params, Nan::New("mmap_memory").ToLocalChecked()).ToLocalChecked(); + auto mmap_memory = params.Get("mmap_memory"); if (mmap_memory.IsEmpty()) return engine_config_ptr(); - if (!memory_file->IsUndefined()) + if (!memory_file.IsUndefined()) { - if (path->IsUndefined()) + if (path.IsUndefined()) { - Nan::ThrowError("memory_file option requires a path to a file."); + ThrowError(args.Env(), "memory_file option requires a path to a file."); return engine_config_ptr(); } - engine_config->memory_file = - *Nan::Utf8String(Nan::To(memory_file).ToLocalChecked()); + engine_config->memory_file = memory_file.ToString().Utf8Value(); } - auto dataset_name = - Nan::Get(params, Nan::New("dataset_name").ToLocalChecked()).ToLocalChecked(); + auto dataset_name = params.Get("dataset_name"); if (dataset_name.IsEmpty()) return engine_config_ptr(); - if (!dataset_name->IsUndefined()) + if (!dataset_name.IsUndefined()) { - if (dataset_name->IsString()) + if (dataset_name.IsString()) { - engine_config->dataset_name = - *Nan::Utf8String(Nan::To(dataset_name).ToLocalChecked()); + engine_config->dataset_name = dataset_name.ToString().Utf8Value(); } else { - Nan::ThrowError("dataset_name needs to be a string"); + ThrowError(args.Env(), "dataset_name needs to be a string"); return engine_config_ptr(); } } - if (!path->IsUndefined()) + if (!path.IsUndefined()) { - engine_config->storage_config = - osrm::StorageConfig(*Nan::Utf8String(Nan::To(path).ToLocalChecked())); + engine_config->storage_config = osrm::StorageConfig(path.ToString().Utf8Value()); engine_config->use_shared_memory = false; } - if (!shared_memory->IsUndefined()) + if (!shared_memory.IsUndefined()) { - if (shared_memory->IsBoolean()) + if (shared_memory.IsBoolean()) { - engine_config->use_shared_memory = Nan::To(shared_memory).FromJust(); + engine_config->use_shared_memory = shared_memory.ToBoolean().Value(); } else { - Nan::ThrowError("Shared_memory option must be a boolean"); + ThrowError(args.Env(), "Shared_memory option must be a boolean"); return engine_config_ptr(); } } - if (!mmap_memory->IsUndefined()) + if (!mmap_memory.IsUndefined()) { - if (mmap_memory->IsBoolean()) + if (mmap_memory.IsBoolean()) { - engine_config->use_mmap = Nan::To(mmap_memory).FromJust(); + engine_config->use_mmap = mmap_memory.ToBoolean().Value(); } else { - Nan::ThrowError("mmap_memory option must be a boolean"); + ThrowError(args.Env(), "mmap_memory option must be a boolean"); return engine_config_ptr(); } } - if (path->IsUndefined() && !engine_config->use_shared_memory) + if (path.IsUndefined() && !engine_config->use_shared_memory) { - Nan::ThrowError("Shared_memory must be enabled if no path is " - "specified"); + ThrowError(args.Env(), + "Shared_memory must be enabled if no path is " + "specified"); return engine_config_ptr(); } - auto algorithm = Nan::Get(params, Nan::New("algorithm").ToLocalChecked()).ToLocalChecked(); + auto algorithm = params.Get("algorithm"); if (algorithm.IsEmpty()) return engine_config_ptr(); - if (algorithm->IsString()) + if (algorithm.IsString()) { - auto algorithm_str = Nan::To(algorithm).ToLocalChecked(); - if (*Nan::Utf8String(algorithm_str) == std::string("CH")) + auto algorithm_str = algorithm.ToString().Utf8Value(); + if (algorithm_str == "CH") { engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; } - else if (*Nan::Utf8String(algorithm_str) == std::string("CoreCH")) + else if (algorithm_str == "CoreCH") { engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; } - else if (*Nan::Utf8String(algorithm_str) == std::string("MLD")) + else if (algorithm_str == "MLD") { engine_config->algorithm = osrm::EngineConfig::Algorithm::MLD; } else { - Nan::ThrowError("algorithm option must be one of 'CH', 'CoreCH', or 'MLD'."); + ThrowError(args.Env(), "algorithm option must be one of 'CH', 'CoreCH', or 'MLD'."); return engine_config_ptr(); } } - else if (!algorithm->IsUndefined()) + else if (!algorithm.IsUndefined()) { - Nan::ThrowError("algorithm option must be a string and one of 'CH', 'CoreCH', or 'MLD'."); + ThrowError(args.Env(), + "algorithm option must be a string and one of 'CH', 'CoreCH', or 'MLD'."); return engine_config_ptr(); } // Set EngineConfig system-wide limits on construction, if requested - auto max_locations_trip = - Nan::Get(params, Nan::New("max_locations_trip").ToLocalChecked()).ToLocalChecked(); - auto max_locations_viaroute = - Nan::Get(params, Nan::New("max_locations_viaroute").ToLocalChecked()).ToLocalChecked(); - auto max_locations_distance_table = - Nan::Get(params, Nan::New("max_locations_distance_table").ToLocalChecked()) - .ToLocalChecked(); - auto max_locations_map_matching = - Nan::Get(params, Nan::New("max_locations_map_matching").ToLocalChecked()).ToLocalChecked(); - auto max_results_nearest = - Nan::Get(params, Nan::New("max_results_nearest").ToLocalChecked()).ToLocalChecked(); - auto max_alternatives = - Nan::Get(params, Nan::New("max_alternatives").ToLocalChecked()).ToLocalChecked(); - auto max_radius_map_matching = - Nan::Get(params, Nan::New("max_radius_map_matching").ToLocalChecked()).ToLocalChecked(); + auto max_locations_trip = params.Get("max_locations_trip"); + auto max_locations_viaroute = params.Get("max_locations_viaroute"); + auto max_locations_distance_table = params.Get("max_locations_distance_table"); + auto max_locations_map_matching = params.Get("max_locations_map_matching"); + auto max_results_nearest = params.Get("max_results_nearest"); + auto max_alternatives = params.Get("max_alternatives"); + auto max_radius_map_matching = params.Get("max_radius_map_matching"); - if (!max_locations_trip->IsUndefined() && !max_locations_trip->IsNumber()) + if (!max_locations_trip.IsUndefined() && !max_locations_trip.IsNumber()) { - Nan::ThrowError("max_locations_trip must be an integral number"); + ThrowError(args.Env(), "max_locations_trip must be an integral number"); return engine_config_ptr(); } - if (!max_locations_viaroute->IsUndefined() && !max_locations_viaroute->IsNumber()) + if (!max_locations_viaroute.IsUndefined() && !max_locations_viaroute.IsNumber()) { - Nan::ThrowError("max_locations_viaroute must be an integral number"); + ThrowError(args.Env(), "max_locations_viaroute must be an integral number"); return engine_config_ptr(); } - if (!max_locations_distance_table->IsUndefined() && !max_locations_distance_table->IsNumber()) + if (!max_locations_distance_table.IsUndefined() && !max_locations_distance_table.IsNumber()) { - Nan::ThrowError("max_locations_distance_table must be an integral number"); + ThrowError(args.Env(), "max_locations_distance_table must be an integral number"); return engine_config_ptr(); } - if (!max_locations_map_matching->IsUndefined() && !max_locations_map_matching->IsNumber()) + if (!max_locations_map_matching.IsUndefined() && !max_locations_map_matching.IsNumber()) { - Nan::ThrowError("max_locations_map_matching must be an integral number"); + ThrowError(args.Env(), "max_locations_map_matching must be an integral number"); return engine_config_ptr(); } - if (!max_results_nearest->IsUndefined() && !max_results_nearest->IsNumber()) + if (!max_results_nearest.IsUndefined() && !max_results_nearest.IsNumber()) { - Nan::ThrowError("max_results_nearest must be an integral number"); + ThrowError(args.Env(), "max_results_nearest must be an integral number"); return engine_config_ptr(); } - if (!max_alternatives->IsUndefined() && !max_alternatives->IsNumber()) + if (!max_alternatives.IsUndefined() && !max_alternatives.IsNumber()) { - Nan::ThrowError("max_alternatives must be an integral number"); + ThrowError(args.Env(), "max_alternatives must be an integral number"); return engine_config_ptr(); } - if (max_locations_trip->IsNumber()) - engine_config->max_locations_trip = Nan::To(max_locations_trip).FromJust(); - if (max_locations_viaroute->IsNumber()) - engine_config->max_locations_viaroute = Nan::To(max_locations_viaroute).FromJust(); - if (max_locations_distance_table->IsNumber()) + if (max_locations_trip.IsNumber()) + engine_config->max_locations_trip = max_locations_trip.ToNumber().Int32Value(); + if (max_locations_viaroute.IsNumber()) + engine_config->max_locations_viaroute = max_locations_viaroute.ToNumber().Int32Value(); + if (max_locations_distance_table.IsNumber()) engine_config->max_locations_distance_table = - Nan::To(max_locations_distance_table).FromJust(); - if (max_locations_map_matching->IsNumber()) + max_locations_distance_table.ToNumber().Int32Value(); + if (max_locations_map_matching.IsNumber()) engine_config->max_locations_map_matching = - Nan::To(max_locations_map_matching).FromJust(); - if (max_results_nearest->IsNumber()) - engine_config->max_results_nearest = Nan::To(max_results_nearest).FromJust(); - if (max_alternatives->IsNumber()) - engine_config->max_alternatives = Nan::To(max_alternatives).FromJust(); - if (max_radius_map_matching->IsNumber()) - engine_config->max_radius_map_matching = - Nan::To(max_radius_map_matching).FromJust(); + max_locations_map_matching.ToNumber().Int32Value(); + if (max_results_nearest.IsNumber()) + engine_config->max_results_nearest = max_results_nearest.ToNumber().Int32Value(); + if (max_alternatives.IsNumber()) + engine_config->max_alternatives = max_alternatives.ToNumber().Int32Value(); + if (max_radius_map_matching.IsNumber()) + engine_config->max_radius_map_matching = max_radius_map_matching.ToNumber().DoubleValue(); return engine_config; } inline boost::optional> -parseCoordinateArray(const v8::Local &coordinates_array) +parseCoordinateArray(const Napi::Array &coordinates_array) { - Nan::HandleScope scope; + Napi::HandleScope scope(coordinates_array.Env()); boost::optional> resulting_coordinates; std::vector temp_coordinates; - for (uint32_t i = 0; i < coordinates_array->Length(); ++i) + for (uint32_t i = 0; i < coordinates_array.Length(); ++i) { - v8::Local coordinate = Nan::Get(coordinates_array, i).ToLocalChecked(); + Napi::Value coordinate = coordinates_array.Get(i); if (coordinate.IsEmpty()) return resulting_coordinates; - if (!coordinate->IsArray()) + if (!coordinate.IsArray()) { - Nan::ThrowError("Coordinates must be an array of (lon/lat) pairs"); + ThrowError(coordinates_array.Env(), "Coordinates must be an array of (lon/lat) pairs"); return resulting_coordinates; } - v8::Local coordinate_pair = v8::Local::Cast(coordinate); - if (coordinate_pair->Length() != 2) + Napi::Array coordinate_pair = coordinate.As(); + if (coordinate_pair.Length() != 2) { - Nan::ThrowError("Coordinates must be an array of (lon/lat) pairs"); + ThrowError(coordinates_array.Env(), "Coordinates must be an array of (lon/lat) pairs"); return resulting_coordinates; } - if (!Nan::Get(coordinate_pair, 0).ToLocalChecked()->IsNumber() || - !Nan::Get(coordinate_pair, 1).ToLocalChecked()->IsNumber()) + if (!coordinate_pair.Get(static_cast(0)).IsNumber() || + !coordinate_pair.Get(static_cast(1)).IsNumber()) { - Nan::ThrowError("Each member of a coordinate pair must be a number"); + ThrowError(coordinates_array.Env(), + "Each member of a coordinate pair must be a number"); return resulting_coordinates; } - double lon = Nan::To(Nan::Get(coordinate_pair, 0).ToLocalChecked()).FromJust(); - double lat = Nan::To(Nan::Get(coordinate_pair, 1).ToLocalChecked()).FromJust(); + double lon = coordinate_pair.Get(static_cast(0)).As().DoubleValue(); + double lat = coordinate_pair.Get(static_cast(1)).As().DoubleValue(); if (std::isnan(lon) || std::isnan(lat) || std::isinf(lon) || std::isinf(lat)) { - Nan::ThrowError("Lng/Lat coordinates must be valid numbers"); + ThrowError(coordinates_array.Env(), "Lng/Lat coordinates must be valid numbers"); return resulting_coordinates; } if (lon > 180 || lon < -180 || lat > 90 || lat < -90) { - Nan::ThrowError("Lng/Lat coordinates must be within world bounds " - "(-180 < lng < 180, -90 < lat < 90)"); + ThrowError(coordinates_array.Env(), + "Lng/Lat coordinates must be within world bounds " + "(-180 < lng < 180, -90 < lat < 90)"); return resulting_coordinates; } @@ -388,47 +398,46 @@ parseCoordinateArray(const v8::Local &coordinates_array) // Parses all the non-service specific parameters template -inline bool argumentsToParameter(const Nan::FunctionCallbackInfo &args, +inline bool argumentsToParameter(const Napi::CallbackInfo &args, ParamType ¶ms, bool requires_multiple_coordinates) { - Nan::HandleScope scope; + Napi::HandleScope scope(args.Env()); if (args.Length() < 2) { - Nan::ThrowTypeError("Two arguments required"); + ThrowTypeError(args.Env(), "Two arguments required"); return false; } - if (!args[0]->IsObject()) + if (!args[0].IsObject()) { - Nan::ThrowTypeError("First arg must be an object"); + ThrowTypeError(args.Env(), "First arg must be an object"); return false; } - v8::Local obj = Nan::To(args[0]).ToLocalChecked(); + Napi::Object obj = args[0].As(); - v8::Local coordinates = - Nan::Get(obj, Nan::New("coordinates").ToLocalChecked()).ToLocalChecked(); + Napi::Value coordinates = obj.Get("coordinates"); if (coordinates.IsEmpty()) return false; - if (coordinates->IsUndefined()) + if (coordinates.IsUndefined()) { - Nan::ThrowError("Must provide a coordinates property"); + ThrowError(args.Env(), "Must provide a coordinates property"); return false; } - else if (coordinates->IsArray()) + else if (coordinates.IsArray()) { - auto coordinates_array = v8::Local::Cast(coordinates); - if (coordinates_array->Length() < 2 && requires_multiple_coordinates) + auto coordinates_array = coordinates.As(); + if (coordinates_array.Length() < 2 && requires_multiple_coordinates) { - Nan::ThrowError("At least two coordinates must be provided"); + ThrowError(args.Env(), "At least two coordinates must be provided"); return false; } - else if (!requires_multiple_coordinates && coordinates_array->Length() != 1) + else if (!requires_multiple_coordinates && coordinates_array.Length() != 1) { - Nan::ThrowError("Exactly one coordinate pair must be provided"); + ThrowError(args.Env(), "Exactly one coordinate pair must be provided"); return false; } auto maybe_coordinates = parseCoordinateArray(coordinates_array); @@ -443,49 +452,47 @@ inline bool argumentsToParameter(const Nan::FunctionCallbackInfo &arg return false; } } - else if (!coordinates->IsUndefined()) + else if (!coordinates.IsUndefined()) { - BOOST_ASSERT(!coordinates->IsArray()); - Nan::ThrowError("Coordinates must be an array of (lon/lat) pairs"); + BOOST_ASSERT(!coordinates.IsArray()); + ThrowError(args.Env(), "Coordinates must be an array of (lon/lat) pairs"); return false; } - if (Nan::Has(obj, Nan::New("approaches").ToLocalChecked()).FromJust()) + if (obj.Has("approaches")) { - v8::Local approaches = - Nan::Get(obj, Nan::New("approaches").ToLocalChecked()).ToLocalChecked(); + Napi::Value approaches = obj.Get("approaches"); if (approaches.IsEmpty()) return false; - if (!approaches->IsArray()) + if (!approaches.IsArray()) { - Nan::ThrowError("Approaches must be an arrays of strings"); + ThrowError(args.Env(), "Approaches must be an arrays of strings"); return false; } - auto approaches_array = v8::Local::Cast(approaches); + auto approaches_array = approaches.As(); - if (approaches_array->Length() != params->coordinates.size()) + if (approaches_array.Length() != params->coordinates.size()) { - Nan::ThrowError("Approaches array must have the same length as coordinates array"); + ThrowError(args.Env(), + "Approaches array must have the same length as coordinates array"); return false; } - for (uint32_t i = 0; i < approaches_array->Length(); ++i) + for (uint32_t i = 0; i < approaches_array.Length(); ++i) { - v8::Local approach_raw = Nan::Get(approaches_array, i).ToLocalChecked(); + Napi::Value approach_raw = approaches_array.Get(i); if (approach_raw.IsEmpty()) return false; - if (approach_raw->IsNull()) + if (approach_raw.IsNull()) { params->approaches.emplace_back(); } - else if (approach_raw->IsString()) + else if (approach_raw.IsString()) { - const Nan::Utf8String approach_utf8str(approach_raw); - std::string approach_str{*approach_utf8str, - *approach_utf8str + approach_utf8str.length()}; + std::string approach_str = approach_raw.ToString().Utf8Value(); if (approach_str == "curb") { params->approaches.push_back(osrm::Approach::CURB); @@ -496,69 +503,69 @@ inline bool argumentsToParameter(const Nan::FunctionCallbackInfo &arg } else { - Nan::ThrowError("'approaches' param must be one of [curb, unrestricted]"); + ThrowError(args.Env(), + "'approaches' param must be one of [curb, unrestricted]"); return false; } } else { - Nan::ThrowError("Approach must be a string: [curb, unrestricted] or null"); + ThrowError(args.Env(), "Approach must be a string: [curb, unrestricted] or null"); return false; } } } - if (Nan::Has(obj, Nan::New("bearings").ToLocalChecked()).FromJust()) + if (obj.Has("bearings")) { - v8::Local bearings = - Nan::Get(obj, Nan::New("bearings").ToLocalChecked()).ToLocalChecked(); + Napi::Value bearings = obj.Get("bearings"); if (bearings.IsEmpty()) return false; - if (!bearings->IsArray()) + if (!bearings.IsArray()) { - Nan::ThrowError("Bearings must be an array of arrays of numbers"); + ThrowError(args.Env(), "Bearings must be an array of arrays of numbers"); return false; } - auto bearings_array = v8::Local::Cast(bearings); + auto bearings_array = bearings.As(); - if (bearings_array->Length() != params->coordinates.size()) + if (bearings_array.Length() != params->coordinates.size()) { - Nan::ThrowError("Bearings array must have the same length as coordinates array"); + ThrowError(args.Env(), "Bearings array must have the same length as coordinates array"); return false; } - for (uint32_t i = 0; i < bearings_array->Length(); ++i) + for (uint32_t i = 0; i < bearings_array.Length(); ++i) { - v8::Local bearing_raw = Nan::Get(bearings_array, i).ToLocalChecked(); + Napi::Value bearing_raw = bearings_array.Get(i); if (bearing_raw.IsEmpty()) return false; - if (bearing_raw->IsNull()) + if (bearing_raw.IsNull()) { params->bearings.emplace_back(); } - else if (bearing_raw->IsArray()) + else if (bearing_raw.IsArray()) { - auto bearing_pair = v8::Local::Cast(bearing_raw); - if (bearing_pair->Length() == 2) + auto bearing_pair = bearing_raw.As(); + if (bearing_pair.Length() == 2) { - if (!Nan::Get(bearing_pair, 0).ToLocalChecked()->IsNumber() || - !Nan::Get(bearing_pair, 1).ToLocalChecked()->IsNumber()) + if (!bearing_pair.Get(static_cast(0)).IsNumber() || + !bearing_pair.Get(static_cast(1)).IsNumber()) { - Nan::ThrowError("Bearing values need to be numbers in range 0..360"); + ThrowError(args.Env(), "Bearing values need to be numbers in range 0..360"); return false; } const auto bearing = - Nan::To(Nan::Get(bearing_pair, 0).ToLocalChecked()).FromJust(); + bearing_pair.Get(static_cast(0)).ToNumber().Int32Value(); const auto range = - Nan::To(Nan::Get(bearing_pair, 1).ToLocalChecked()).FromJust(); + bearing_pair.Get(static_cast(1)).ToNumber().Int32Value(); if (bearing < 0 || bearing > 360 || range < 0 || range > 180) { - Nan::ThrowError("Bearing values need to be in range 0..360, 0..180"); + ThrowError(args.Env(), "Bearing values need to be in range 0..360, 0..180"); return false; } @@ -567,192 +574,187 @@ inline bool argumentsToParameter(const Nan::FunctionCallbackInfo &arg } else { - Nan::ThrowError("Bearing must be an array of [bearing, range] or null"); + ThrowError(args.Env(), "Bearing must be an array of [bearing, range] or null"); return false; } } else { - Nan::ThrowError("Bearing must be an array of [bearing, range] or null"); + ThrowError(args.Env(), "Bearing must be an array of [bearing, range] or null"); return false; } } } - if (Nan::Has(obj, Nan::New("hints").ToLocalChecked()).FromJust()) + if (obj.Has("hints")) { - v8::Local hints = - Nan::Get(obj, Nan::New("hints").ToLocalChecked()).ToLocalChecked(); + Napi::Value hints = obj.Get("hints"); if (hints.IsEmpty()) return false; - if (!hints->IsArray()) + if (!hints.IsArray()) { - Nan::ThrowError("Hints must be an array of strings/null"); + ThrowError(args.Env(), "Hints must be an array of strings/null"); return false; } - v8::Local hints_array = v8::Local::Cast(hints); + Napi::Array hints_array = hints.As(); - if (hints_array->Length() != params->coordinates.size()) + if (hints_array.Length() != params->coordinates.size()) { - Nan::ThrowError("Hints array must have the same length as coordinates array"); + ThrowError(args.Env(), "Hints array must have the same length as coordinates array"); return false; } - for (uint32_t i = 0; i < hints_array->Length(); ++i) + for (uint32_t i = 0; i < hints_array.Length(); ++i) { - v8::Local hint = Nan::Get(hints_array, i).ToLocalChecked(); + Napi::Value hint = hints_array.Get(i); if (hint.IsEmpty()) return false; - if (hint->IsString()) + if (hint.IsString()) { - if (Nan::To(hint).ToLocalChecked()->Length() == 0) + if (hint.ToString().Utf8Value().length() == 0) { - Nan::ThrowError("Hint cannot be an empty string"); + ThrowError(args.Env(), "Hint cannot be an empty string"); return false; } - params->hints.push_back(osrm::engine::Hint::FromBase64(*Nan::Utf8String(hint))); + params->hints.emplace_back( + osrm::engine::Hint::FromBase64(hint.ToString().Utf8Value())); } - else if (hint->IsNull()) + else if (hint.IsNull()) { params->hints.emplace_back(); } else { - Nan::ThrowError("Hint must be null or string"); + ThrowError(args.Env(), "Hint must be null or string"); return false; } } } - if (Nan::Has(obj, Nan::New("radiuses").ToLocalChecked()).FromJust()) + if (obj.Has("radiuses")) { - v8::Local radiuses = - Nan::Get(obj, Nan::New("radiuses").ToLocalChecked()).ToLocalChecked(); + Napi::Value radiuses = obj.Get("radiuses"); if (radiuses.IsEmpty()) return false; - if (!radiuses->IsArray()) + if (!radiuses.IsArray()) { - Nan::ThrowError("Radiuses must be an array of non-negative doubles or null"); + ThrowError(args.Env(), "Radiuses must be an array of non-negative doubles or null"); return false; } - v8::Local radiuses_array = v8::Local::Cast(radiuses); + Napi::Array radiuses_array = radiuses.As(); - if (radiuses_array->Length() != params->coordinates.size()) + if (radiuses_array.Length() != params->coordinates.size()) { - Nan::ThrowError("Radiuses array must have the same length as coordinates array"); + ThrowError(args.Env(), "Radiuses array must have the same length as coordinates array"); return false; } - for (uint32_t i = 0; i < radiuses_array->Length(); ++i) + for (uint32_t i = 0; i < radiuses_array.Length(); ++i) { - v8::Local radius = Nan::Get(radiuses_array, i).ToLocalChecked(); + Napi::Value radius = radiuses_array.Get(i); if (radius.IsEmpty()) return false; - if (radius->IsNull()) + if (radius.IsNull()) { params->radiuses.emplace_back(); } - else if (radius->IsNumber() && Nan::To(radius).FromJust() >= 0) + else if (radius.IsNumber() && radius.ToNumber().DoubleValue() >= 0) { - params->radiuses.push_back(Nan::To(radius).FromJust()); + params->radiuses.push_back(radius.ToNumber().DoubleValue()); } else { - Nan::ThrowError("Radius must be non-negative double or null"); + ThrowError(args.Env(), "Radius must be non-negative double or null"); return false; } } } - if (Nan::Has(obj, Nan::New("generate_hints").ToLocalChecked()).FromJust()) + if (obj.Has("generate_hints")) { - v8::Local generate_hints = - Nan::Get(obj, Nan::New("generate_hints").ToLocalChecked()).ToLocalChecked(); + Napi::Value generate_hints = obj.Get("generate_hints"); if (generate_hints.IsEmpty()) return false; - if (!generate_hints->IsBoolean()) + if (!generate_hints.IsBoolean()) { - Nan::ThrowError("generate_hints must be of type Boolean"); + ThrowError(args.Env(), "generate_hints must be of type Boolean"); return false; } - params->generate_hints = Nan::To(generate_hints).FromJust(); + params->generate_hints = generate_hints.ToBoolean().Value(); } - if (Nan::Has(obj, Nan::New("skip_waypoints").ToLocalChecked()).FromJust()) + if (obj.Has("skip_waypoints")) { - v8::Local skip_waypoints = - Nan::Get(obj, Nan::New("skip_waypoints").ToLocalChecked()).ToLocalChecked(); + Napi::Value skip_waypoints = obj.Get("skip_waypoints"); if (skip_waypoints.IsEmpty()) return false; - if (!skip_waypoints->IsBoolean()) + if (!skip_waypoints.IsBoolean()) { - Nan::ThrowError("skip_waypoints must be of type Boolean"); + ThrowError(args.Env(), "skip_waypoints must be of type Boolean"); return false; } - params->skip_waypoints = Nan::To(skip_waypoints).FromJust(); + params->skip_waypoints = skip_waypoints.ToBoolean().Value(); } - if (Nan::Has(obj, Nan::New("exclude").ToLocalChecked()).FromJust()) + if (obj.Has("exclude")) { - v8::Local exclude = - Nan::Get(obj, Nan::New("exclude").ToLocalChecked()).ToLocalChecked(); + Napi::Value exclude = obj.Get("exclude"); if (exclude.IsEmpty()) return false; - if (!exclude->IsArray()) + if (!exclude.IsArray()) { - Nan::ThrowError("Exclude must be an array of strings or empty"); + ThrowError(args.Env(), "Exclude must be an array of strings or empty"); return false; } - v8::Local exclude_array = v8::Local::Cast(exclude); + Napi::Array exclude_array = exclude.As(); - for (uint32_t i = 0; i < exclude_array->Length(); ++i) + for (uint32_t i = 0; i < exclude_array.Length(); ++i) { - v8::Local class_name = Nan::Get(exclude_array, i).ToLocalChecked(); + Napi::Value class_name = exclude_array.Get(i); if (class_name.IsEmpty()) return false; - if (class_name->IsString()) + if (class_name.IsString()) { - std::string class_name_str = *Nan::Utf8String(class_name); - params->exclude.emplace_back(class_name_str); + std::string class_name_str = class_name.ToString().Utf8Value(); + params->exclude.emplace_back(std::move(class_name_str)); } else { - Nan::ThrowError("Exclude must be an array of strings or empty"); + ThrowError(args.Env(), "Exclude must be an array of strings or empty"); return false; } } } - if (Nan::Has(obj, Nan::New("format").ToLocalChecked()).FromJust()) + if (obj.Has("format")) { - v8::Local format = - Nan::Get(obj, Nan::New("format").ToLocalChecked()).ToLocalChecked(); + Napi::Value format = obj.Get("format"); if (format.IsEmpty()) { return false; } - if (!format->IsString()) + if (!format.IsString()) { - Nan::ThrowError("format must be a string: \"json\" or \"flatbuffers\""); + ThrowError(args.Env(), "format must be a string: \"json\" or \"flatbuffers\""); return false; } - std::string format_str = *Nan::Utf8String(format); + std::string format_str = format.ToString().Utf8Value(); if (format_str == "json") { params->format = osrm::engine::api::BaseParameters::OutputFormatType::JSON; @@ -763,25 +765,24 @@ inline bool argumentsToParameter(const Nan::FunctionCallbackInfo &arg } else { - Nan::ThrowError("format must be a string: \"json\" or \"flatbuffers\""); + ThrowError(args.Env(), "format must be a string: \"json\" or \"flatbuffers\""); return false; } } - if (Nan::Has(obj, Nan::New("snapping").ToLocalChecked()).FromJust()) + if (obj.Has("snapping")) { - v8::Local snapping = - Nan::Get(obj, Nan::New("snapping").ToLocalChecked()).ToLocalChecked(); + Napi::Value snapping = obj.Get("snapping"); if (snapping.IsEmpty()) return false; - if (!snapping->IsString()) + if (!snapping.IsString()) { - Nan::ThrowError("Snapping must be a string: [default, any]"); + ThrowError(args.Env(), "Snapping must be a string: [default, any]"); return false; } - const Nan::Utf8String snapping_utf8str(snapping); - std::string snapping_str{*snapping_utf8str, *snapping_utf8str + snapping_utf8str.length()}; + + std::string snapping_str = snapping.ToString().Utf8Value(); if (snapping_str == "default") { @@ -793,7 +794,7 @@ inline bool argumentsToParameter(const Nan::FunctionCallbackInfo &arg } else { - Nan::ThrowError("'snapping' param must be one of [default, any]"); + ThrowError(args.Env(), "'snapping' param must be one of [default, any]"); return false; } } @@ -802,47 +803,44 @@ inline bool argumentsToParameter(const Nan::FunctionCallbackInfo &arg } template -inline bool parseCommonParameters(const v8::Local &obj, ParamType ¶ms) +inline bool parseCommonParameters(const Napi::Object &obj, ParamType ¶ms) { - if (Nan::Has(obj, Nan::New("steps").ToLocalChecked()).FromJust()) + if (obj.Has("steps")) { - auto steps = Nan::Get(obj, Nan::New("steps").ToLocalChecked()).ToLocalChecked(); + auto steps = obj.Get("steps"); if (steps.IsEmpty()) return false; - if (steps->IsBoolean()) + if (steps.IsBoolean()) { - params->steps = Nan::To(steps).FromJust(); + params->steps = steps.ToBoolean().Value(); } else { - Nan::ThrowError("'steps' param must be a boolean"); + ThrowError(obj.Env(), "'steps' param must be a boolean"); return false; } } - if (Nan::Has(obj, Nan::New("annotations").ToLocalChecked()).FromJust()) + if (obj.Has("annotations")) { - auto annotations = Nan::Get(obj, Nan::New("annotations").ToLocalChecked()).ToLocalChecked(); + auto annotations = obj.Get("annotations"); if (annotations.IsEmpty()) return false; - if (annotations->IsBoolean()) + if (annotations.IsBoolean()) { - params->annotations = Nan::To(annotations).FromJust(); + params->annotations = annotations.ToBoolean().Value(); params->annotations_type = params->annotations ? osrm::RouteParameters::AnnotationsType::All : osrm::RouteParameters::AnnotationsType::None; } - else if (annotations->IsArray()) + else if (annotations.IsArray()) { - v8::Local annotations_array = v8::Local::Cast(annotations); - for (std::size_t i = 0; i < annotations_array->Length(); i++) + Napi::Array annotations_array = annotations.As(); + for (std::size_t i = 0; i < annotations_array.Length(); i++) { - const Nan::Utf8String annotations_utf8str( - Nan::Get(annotations_array, i).ToLocalChecked()); - std::string annotations_str{*annotations_utf8str, - *annotations_utf8str + annotations_utf8str.length()}; + std::string annotations_str = annotations_array.Get(i).ToString().Utf8Value(); if (annotations_str == "duration") { @@ -876,7 +874,7 @@ inline bool parseCommonParameters(const v8::Local &obj, ParamType &p } else { - Nan::ThrowError("this 'annotations' param is not supported"); + ThrowError(obj.Env(), "this 'annotations' param is not supported"); return false; } @@ -886,26 +884,23 @@ inline bool parseCommonParameters(const v8::Local &obj, ParamType &p } else { - Nan::ThrowError("this 'annotations' param is not supported"); + ThrowError(obj.Env(), "this 'annotations' param is not supported"); return false; } } - if (Nan::Has(obj, Nan::New("geometries").ToLocalChecked()).FromJust()) + if (obj.Has("geometries")) { - v8::Local geometries = - Nan::Get(obj, Nan::New("geometries").ToLocalChecked()).ToLocalChecked(); + Napi::Value geometries = obj.Get("geometries"); if (geometries.IsEmpty()) return false; - if (!geometries->IsString()) + if (!geometries.IsString()) { - Nan::ThrowError("Geometries must be a string: [polyline, polyline6, geojson]"); + ThrowError(obj.Env(), "Geometries must be a string: [polyline, polyline6, geojson]"); return false; } - const Nan::Utf8String geometries_utf8str(geometries); - std::string geometries_str{*geometries_utf8str, - *geometries_utf8str + geometries_utf8str.length()}; + std::string geometries_str = geometries.ToString().Utf8Value(); if (geometries_str == "polyline") { @@ -921,26 +916,25 @@ inline bool parseCommonParameters(const v8::Local &obj, ParamType &p } else { - Nan::ThrowError("'geometries' param must be one of [polyline, polyline6, geojson]"); + ThrowError(obj.Env(), + "'geometries' param must be one of [polyline, polyline6, geojson]"); return false; } } - if (Nan::Has(obj, Nan::New("overview").ToLocalChecked()).FromJust()) + if (obj.Has("overview")) { - v8::Local overview = - Nan::Get(obj, Nan::New("overview").ToLocalChecked()).ToLocalChecked(); + Napi::Value overview = obj.Get("overview"); if (overview.IsEmpty()) return false; - if (!overview->IsString()) + if (!overview.IsString()) { - Nan::ThrowError("Overview must be a string: [simplified, full, false]"); + ThrowError(obj.Env(), "Overview must be a string: [simplified, full, false]"); return false; } - const Nan::Utf8String overview_utf8str(overview); - std::string overview_str{*overview_utf8str, *overview_utf8str + overview_utf8str.length()}; + std::string overview_str = overview.ToString().Utf8Value(); if (overview_str == "simplified") { @@ -956,7 +950,7 @@ inline bool parseCommonParameters(const v8::Local &obj, ParamType &p } else { - Nan::ThrowError("'overview' param must be one of [simplified, full, false]"); + ThrowError(obj.Env(), "'overview' param must be one of [simplified, full, false]"); return false; } } @@ -965,38 +959,36 @@ inline bool parseCommonParameters(const v8::Local &obj, ParamType &p } inline PluginParameters argumentsToPluginParameters( - const Nan::FunctionCallbackInfo &args, + const Napi::CallbackInfo &args, const boost::optional &output_format = {}) { - if (args.Length() < 3 || !args[1]->IsObject()) + if (args.Length() < 3 || !args[1].IsObject()) { // output to buffer by default for Flatbuffers return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; } - v8::Local obj = Nan::To(args[1]).ToLocalChecked(); - if (Nan::Has(obj, Nan::New("format").ToLocalChecked()).FromJust()) + Napi::Object obj = args[1].As(); + if (obj.Has("format")) { - v8::Local format = - Nan::Get(obj, Nan::New("format").ToLocalChecked()).ToLocalChecked(); + Napi::Value format = obj.Get("format"); if (format.IsEmpty()) { return {}; } - if (!format->IsString()) + if (!format.IsString()) { - Nan::ThrowError("format must be a string: \"object\" or \"buffer\""); + ThrowError(args.Env(), "format must be a string: \"object\" or \"buffer\""); return {}; } - const Nan::Utf8String format_utf8str(format); - std::string format_str{*format_utf8str, *format_utf8str + format_utf8str.length()}; + std::string format_str = format.ToString().Utf8Value(); if (format_str == "object") { if (output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS) { - Nan::ThrowError("Flatbuffers result can only output to buffer."); + ThrowError(args.Env(), "Flatbuffers result can only output to buffer."); return {true}; } return {false}; @@ -1010,13 +1002,14 @@ inline PluginParameters argumentsToPluginParameters( if (output_format && output_format != osrm::engine::api::BaseParameters::OutputFormatType::JSON) { - Nan::ThrowError("Deprecated `json_buffer` can only be used with JSON format"); + ThrowError(args.Env(), + "Deprecated `json_buffer` can only be used with JSON format"); } return {true}; } else { - Nan::ThrowError("format must be a string: \"object\" or \"buffer\""); + ThrowError(args.Env(), "format must be a string: \"object\" or \"buffer\""); return {}; } } @@ -1025,112 +1018,111 @@ inline PluginParameters argumentsToPluginParameters( return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; } -inline route_parameters_ptr -argumentsToRouteParameter(const Nan::FunctionCallbackInfo &args, - bool requires_multiple_coordinates) +inline route_parameters_ptr argumentsToRouteParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) { route_parameters_ptr params = std::make_unique(); bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); if (!has_base_params) return route_parameters_ptr(); - v8::Local obj = Nan::To(args[0]).ToLocalChecked(); + Napi::Object obj = args[0].As(); - if (Nan::Has(obj, Nan::New("continue_straight").ToLocalChecked()).FromJust()) + if (obj.Has("continue_straight")) { - auto value = Nan::Get(obj, Nan::New("continue_straight").ToLocalChecked()).ToLocalChecked(); + auto value = obj.Get("continue_straight"); if (value.IsEmpty()) return route_parameters_ptr(); - if (!value->IsBoolean() && !value->IsNull()) + if (!value.IsBoolean() && !value.IsNull()) { - Nan::ThrowError("'continue_straight' param must be boolean or null"); + ThrowError(args.Env(), "'continue_straight' param must be boolean or null"); return route_parameters_ptr(); } - if (value->IsBoolean()) + if (value.IsBoolean()) { - params->continue_straight = Nan::To(value).FromJust(); + params->continue_straight = value.ToBoolean().Value(); } } - if (Nan::Has(obj, Nan::New("alternatives").ToLocalChecked()).FromJust()) + if (obj.Has("alternatives")) { - auto value = Nan::Get(obj, Nan::New("alternatives").ToLocalChecked()).ToLocalChecked(); + auto value = obj.Get("alternatives"); if (value.IsEmpty()) return route_parameters_ptr(); - if (value->IsBoolean()) + if (value.IsBoolean()) { - params->alternatives = Nan::To(value).FromJust(); - params->number_of_alternatives = Nan::To(value).FromJust() ? 1u : 0u; + params->alternatives = value.ToBoolean().Value(); + params->number_of_alternatives = value.ToBoolean().Value() ? 1u : 0u; } - else if (value->IsNumber()) + else if (value.IsNumber()) { - params->alternatives = Nan::To(value).FromJust(); - params->number_of_alternatives = Nan::To(value).FromJust(); + params->alternatives = value.ToBoolean().Value(); + params->number_of_alternatives = value.ToNumber().Int32Value(); } else { - Nan::ThrowError("'alternatives' param must be boolean or number"); + ThrowError(args.Env(), "'alternatives' param must be boolean or number"); return route_parameters_ptr(); } } - if (Nan::Has(obj, Nan::New("waypoints").ToLocalChecked()).FromJust()) + if (obj.Has("waypoints")) { - v8::Local waypoints = - Nan::Get(obj, Nan::New("waypoints").ToLocalChecked()).ToLocalChecked(); + Napi::Value waypoints = obj.Get("waypoints"); if (waypoints.IsEmpty()) return route_parameters_ptr(); // must be array - if (!waypoints->IsArray()) + if (!waypoints.IsArray()) { - Nan::ThrowError( + ThrowError( + args.Env(), "Waypoints must be an array of integers corresponding to the input coordinates."); return route_parameters_ptr(); } - auto waypoints_array = v8::Local::Cast(waypoints); + auto waypoints_array = waypoints.As(); // must have at least two elements - if (waypoints_array->Length() < 2) + if (waypoints_array.Length() < 2) { - Nan::ThrowError("At least two waypoints must be provided"); + ThrowError(args.Env(), "At least two waypoints must be provided"); return route_parameters_ptr(); } auto coords_size = params->coordinates.size(); - auto waypoints_array_size = waypoints_array->Length(); + auto waypoints_array_size = waypoints_array.Length(); const auto first_index = - Nan::To(Nan::Get(waypoints_array, 0).ToLocalChecked()).FromJust(); + waypoints_array.Get(static_cast(0)).ToNumber().Uint32Value(); const auto last_index = - Nan::To( - Nan::Get(waypoints_array, waypoints_array_size - 1).ToLocalChecked()) - .FromJust(); + waypoints_array.Get(waypoints_array_size - 1).ToNumber().Uint32Value(); if (first_index != 0 || last_index != coords_size - 1) { - Nan::ThrowError("First and last waypoints values must correspond to first and last " - "coordinate indices"); + ThrowError(args.Env(), + "First and last waypoints values must correspond to first and last " + "coordinate indices"); return route_parameters_ptr(); } for (uint32_t i = 0; i < waypoints_array_size; ++i) { - v8::Local waypoint_value = Nan::Get(waypoints_array, i).ToLocalChecked(); + Napi::Value waypoint_value = waypoints_array.Get(i); // all elements must be numbers - if (!waypoint_value->IsNumber()) + if (!waypoint_value.IsNumber()) { - Nan::ThrowError("Waypoint values must be an array of integers"); + ThrowError(args.Env(), "Waypoint values must be an array of integers"); return route_parameters_ptr(); } // check that the waypoint index corresponds with an inpute coordinate - const auto index = Nan::To(waypoint_value).FromJust(); + const auto index = waypoint_value.ToNumber().Uint32Value(); if (index >= coords_size) { - Nan::ThrowError("Waypoints must correspond with the index of an input coordinate"); + ThrowError(args.Env(), + "Waypoints must correspond with the index of an input coordinate"); return route_parameters_ptr(); } - params->waypoints.emplace_back(Nan::To(waypoint_value).FromJust()); + params->waypoints.emplace_back(index); } if (!params->waypoints.empty()) @@ -1139,7 +1131,7 @@ argumentsToRouteParameter(const Nan::FunctionCallbackInfo &args, { if (params->waypoints[i] >= params->waypoints[i + 1]) { - Nan::ThrowError("Waypoints must be supplied in increasing order"); + ThrowError(args.Env(), "Waypoints must be supplied in increasing order"); return route_parameters_ptr(); } } @@ -1155,221 +1147,214 @@ argumentsToRouteParameter(const Nan::FunctionCallbackInfo &args, return params; } -inline tile_parameters_ptr -argumentsToTileParameters(const Nan::FunctionCallbackInfo &args, bool /*unused*/) +inline tile_parameters_ptr argumentsToTileParameters(const Napi::CallbackInfo &args, + bool /*unused*/) { tile_parameters_ptr params = std::make_unique(); if (args.Length() < 2) { - Nan::ThrowTypeError("Coordinate object and callback required"); + ThrowTypeError(args.Env(), "Coordinate object and callback required"); return tile_parameters_ptr(); } - if (!args[0]->IsArray()) + if (!args[0].IsArray()) { - Nan::ThrowTypeError("Parameter must be an array [x, y, z]"); + ThrowTypeError(args.Env(), "Parameter must be an array [x, y, z]"); return tile_parameters_ptr(); } - v8::Local array = v8::Local::Cast(args[0]); + Napi::Array array = args[0].As(); - if (array->Length() != 3) + if (array.Length() != 3) { - Nan::ThrowTypeError("Parameter must be an array [x, y, z]"); + ThrowTypeError(args.Env(), "Parameter must be an array [x, y, z]"); return tile_parameters_ptr(); } - v8::Local x = Nan::Get(array, 0).ToLocalChecked(); - v8::Local y = Nan::Get(array, 1).ToLocalChecked(); - v8::Local z = Nan::Get(array, 2).ToLocalChecked(); + Napi::Value x = array.Get(static_cast(0)); + Napi::Value y = array.Get(static_cast(1)); + Napi::Value z = array.Get(static_cast(2)); if (x.IsEmpty() || y.IsEmpty() || z.IsEmpty()) return tile_parameters_ptr(); - if (!x->IsUint32() && !x->IsUndefined()) + if (!IsUnsignedInteger(x) && !x.IsUndefined()) { - Nan::ThrowError("Tile x coordinate must be unsigned interger"); + ThrowError(args.Env(), "Tile x coordinate must be unsigned interger"); return tile_parameters_ptr(); } - if (!y->IsUint32() && !y->IsUndefined()) + if (!IsUnsignedInteger(y) && !y.IsUndefined()) { - Nan::ThrowError("Tile y coordinate must be unsigned interger"); + ThrowError(args.Env(), "Tile y coordinate must be unsigned interger"); return tile_parameters_ptr(); } - if (!z->IsUint32() && !z->IsUndefined()) + if (!IsUnsignedInteger(z) && !z.IsUndefined()) { - Nan::ThrowError("Tile z coordinate must be unsigned interger"); + ThrowError(args.Env(), "Tile z coordinate must be unsigned interger"); return tile_parameters_ptr(); } - params->x = Nan::To(x).FromJust(); - params->y = Nan::To(y).FromJust(); - params->z = Nan::To(z).FromJust(); + params->x = x.ToNumber().Uint32Value(); + params->y = y.ToNumber().Uint32Value(); + params->z = z.ToNumber().Uint32Value(); if (!params->IsValid()) { - Nan::ThrowError("Invalid tile coordinates"); + ThrowError(args.Env(), "Invalid tile coordinates"); return tile_parameters_ptr(); } return params; } -inline nearest_parameters_ptr -argumentsToNearestParameter(const Nan::FunctionCallbackInfo &args, - bool requires_multiple_coordinates) +inline nearest_parameters_ptr argumentsToNearestParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) { nearest_parameters_ptr params = std::make_unique(); bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); if (!has_base_params) return nearest_parameters_ptr(); - v8::Local obj = Nan::To(args[0]).ToLocalChecked(); + Napi::Object obj = args[0].As(); if (obj.IsEmpty()) return nearest_parameters_ptr(); - if (Nan::Has(obj, Nan::New("number").ToLocalChecked()).FromJust()) + if (obj.Has("number")) { - v8::Local number = - Nan::Get(obj, Nan::New("number").ToLocalChecked()).ToLocalChecked(); + Napi::Value number = obj.Get("number"); - if (!number->IsUint32()) + if (!IsUnsignedInteger(number)) { - Nan::ThrowError("Number must be an integer greater than or equal to 1"); + ThrowError(args.Env(), "Number must be an integer greater than or equal to 1"); return nearest_parameters_ptr(); } else { - unsigned number_value = Nan::To(number).FromJust(); + unsigned number_value = number.ToNumber().Uint32Value(); if (number_value < 1) { - Nan::ThrowError("Number must be an integer greater than or equal to 1"); + ThrowError(args.Env(), "Number must be an integer greater than or equal to 1"); return nearest_parameters_ptr(); } - params->number_of_results = Nan::To(number).FromJust(); + params->number_of_results = number_value; } } return params; } -inline table_parameters_ptr -argumentsToTableParameter(const Nan::FunctionCallbackInfo &args, - bool requires_multiple_coordinates) +inline table_parameters_ptr argumentsToTableParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) { table_parameters_ptr params = std::make_unique(); bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); if (!has_base_params) return table_parameters_ptr(); - v8::Local obj = Nan::To(args[0]).ToLocalChecked(); + Napi::Object obj = args[0].As(); if (obj.IsEmpty()) return table_parameters_ptr(); - if (Nan::Has(obj, Nan::New("sources").ToLocalChecked()).FromJust()) + if (obj.Has("sources")) { - v8::Local sources = - Nan::Get(obj, Nan::New("sources").ToLocalChecked()).ToLocalChecked(); + Napi::Value sources = obj.Get("sources"); if (sources.IsEmpty()) return table_parameters_ptr(); - if (!sources->IsArray()) + if (!sources.IsArray()) { - Nan::ThrowError("Sources must be an array of indices (or undefined)"); + ThrowError(args.Env(), "Sources must be an array of indices (or undefined)"); return table_parameters_ptr(); } - v8::Local sources_array = v8::Local::Cast(sources); - for (uint32_t i = 0; i < sources_array->Length(); ++i) + Napi::Array sources_array = sources.As(); + for (uint32_t i = 0; i < sources_array.Length(); ++i) { - v8::Local source = Nan::Get(sources_array, i).ToLocalChecked(); + Napi::Value source = sources_array.Get(i); if (source.IsEmpty()) return table_parameters_ptr(); - if (source->IsUint32()) + if (IsUnsignedInteger(source)) { - size_t source_value = Nan::To(source).FromJust(); + size_t source_value = source.ToNumber().Uint32Value(); if (source_value >= params->coordinates.size()) { - Nan::ThrowError("Source indices must be less than the number of coordinates"); + ThrowError(args.Env(), + "Source indices must be less than the number of coordinates"); return table_parameters_ptr(); } - params->sources.push_back(Nan::To(source).FromJust()); + params->sources.push_back(source.ToNumber().Uint32Value()); } else { - Nan::ThrowError("Source must be an integer"); + ThrowError(args.Env(), "Source must be an integer"); return table_parameters_ptr(); } } } - if (Nan::Has(obj, Nan::New("destinations").ToLocalChecked()).FromJust()) + if (obj.Has("destinations")) { - v8::Local destinations = - Nan::Get(obj, Nan::New("destinations").ToLocalChecked()).ToLocalChecked(); + Napi::Value destinations = obj.Get("destinations"); if (destinations.IsEmpty()) return table_parameters_ptr(); - if (!destinations->IsArray()) + if (!destinations.IsArray()) { - Nan::ThrowError("Destinations must be an array of indices (or undefined)"); + ThrowError(args.Env(), "Destinations must be an array of indices (or undefined)"); return table_parameters_ptr(); } - v8::Local destinations_array = v8::Local::Cast(destinations); - for (uint32_t i = 0; i < destinations_array->Length(); ++i) + Napi::Array destinations_array = destinations.As(); + for (uint32_t i = 0; i < destinations_array.Length(); ++i) { - v8::Local destination = Nan::Get(destinations_array, i).ToLocalChecked(); + Napi::Value destination = destinations_array.Get(i); if (destination.IsEmpty()) return table_parameters_ptr(); - if (destination->IsUint32()) + if (IsUnsignedInteger(destination)) { - size_t destination_value = Nan::To(destination).FromJust(); + size_t destination_value = destination.ToNumber().Uint32Value(); if (destination_value >= params->coordinates.size()) { - Nan::ThrowError("Destination indices must be less than the number " - "of coordinates"); + ThrowError(args.Env(), + "Destination indices must be less than the number " + "of coordinates"); return table_parameters_ptr(); } - params->destinations.push_back(Nan::To(destination).FromJust()); + params->destinations.push_back(destination_value); } else { - Nan::ThrowError("Destination must be an integer"); + ThrowError(args.Env(), "Destination must be an integer"); return table_parameters_ptr(); } } } - if (Nan::Has(obj, Nan::New("annotations").ToLocalChecked()).FromJust()) + if (obj.Has("annotations")) { - v8::Local annotations = - Nan::Get(obj, Nan::New("annotations").ToLocalChecked()).ToLocalChecked(); + Napi::Value annotations = obj.Get("annotations"); if (annotations.IsEmpty()) return table_parameters_ptr(); - if (!annotations->IsArray()) + if (!annotations.IsArray()) { - Nan::ThrowError( - "Annotations must an array containing 'duration' or 'distance', or both"); + ThrowError(args.Env(), + "Annotations must an array containing 'duration' or 'distance', or both"); return table_parameters_ptr(); } params->annotations = osrm::TableParameters::AnnotationsType::None; - v8::Local annotations_array = v8::Local::Cast(annotations); - for (std::size_t i = 0; i < annotations_array->Length(); ++i) + Napi::Array annotations_array = annotations.As(); + for (std::size_t i = 0; i < annotations_array.Length(); ++i) { - const Nan::Utf8String annotations_utf8str( - Nan::Get(annotations_array, i).ToLocalChecked()); - std::string annotations_str{*annotations_utf8str, - *annotations_utf8str + annotations_utf8str.length()}; + std::string annotations_str = annotations_array.Get(i).ToString().Utf8Value(); if (annotations_str == "duration") { @@ -1383,43 +1368,41 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo &args, } else { - Nan::ThrowError("this 'annotations' param is not supported"); + ThrowError(args.Env(), "this 'annotations' param is not supported"); return table_parameters_ptr(); } } } - if (Nan::Has(obj, Nan::New("fallback_speed").ToLocalChecked()).FromJust()) + if (obj.Has("fallback_speed")) { - auto fallback_speed = - Nan::Get(obj, Nan::New("fallback_speed").ToLocalChecked()).ToLocalChecked(); + auto fallback_speed = obj.Get("fallback_speed"); - if (!fallback_speed->IsNumber()) + if (!fallback_speed.IsNumber()) { - Nan::ThrowError("fallback_speed must be a number"); + ThrowError(args.Env(), "fallback_speed must be a number"); return table_parameters_ptr(); } - else if (Nan::To(fallback_speed).FromJust() <= 0) + else if (fallback_speed.ToNumber().DoubleValue() <= 0) { - Nan::ThrowError("fallback_speed must be > 0"); + ThrowError(args.Env(), "fallback_speed must be > 0"); return table_parameters_ptr(); } - params->fallback_speed = Nan::To(fallback_speed).FromJust(); + params->fallback_speed = fallback_speed.ToNumber().DoubleValue(); } - if (Nan::Has(obj, Nan::New("fallback_coordinate").ToLocalChecked()).FromJust()) + if (obj.Has("fallback_coordinate")) { - auto fallback_coordinate = - Nan::Get(obj, Nan::New("fallback_coordinate").ToLocalChecked()).ToLocalChecked(); + auto fallback_coordinate = obj.Get("fallback_coordinate"); - if (!fallback_coordinate->IsString()) + if (!fallback_coordinate.IsString()) { - Nan::ThrowError("fallback_coordinate must be a string: [input, snapped]"); + ThrowError(args.Env(), "fallback_coordinate must be a string: [input, snapped]"); return table_parameters_ptr(); } - std::string fallback_coordinate_str = *Nan::Utf8String(fallback_coordinate); + std::string fallback_coordinate_str = fallback_coordinate.ToString().Utf8Value(); if (fallback_coordinate_str == "snapped") { @@ -1432,43 +1415,41 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo &args, } else { - Nan::ThrowError("'fallback_coordinate' param must be one of [input, snapped]"); + ThrowError(args.Env(), "'fallback_coordinate' param must be one of [input, snapped]"); return table_parameters_ptr(); } } - if (Nan::Has(obj, Nan::New("scale_factor").ToLocalChecked()).FromJust()) + if (obj.Has("scale_factor")) { - auto scale_factor = - Nan::Get(obj, Nan::New("scale_factor").ToLocalChecked()).ToLocalChecked(); + auto scale_factor = obj.Get("scale_factor"); - if (!scale_factor->IsNumber()) + if (!scale_factor.IsNumber()) { - Nan::ThrowError("scale_factor must be a number"); + ThrowError(args.Env(), "scale_factor must be a number"); return table_parameters_ptr(); } - else if (Nan::To(scale_factor).FromJust() <= 0) + else if (scale_factor.ToNumber().DoubleValue() <= 0) { - Nan::ThrowError("scale_factor must be > 0"); + ThrowError(args.Env(), "scale_factor must be > 0"); return table_parameters_ptr(); } - params->scale_factor = Nan::To(scale_factor).FromJust(); + params->scale_factor = scale_factor.ToNumber().DoubleValue(); } return params; } -inline trip_parameters_ptr -argumentsToTripParameter(const Nan::FunctionCallbackInfo &args, - bool requires_multiple_coordinates) +inline trip_parameters_ptr argumentsToTripParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) { trip_parameters_ptr params = std::make_unique(); bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); if (!has_base_params) return trip_parameters_ptr(); - v8::Local obj = Nan::To(args[0]).ToLocalChecked(); + Napi::Object obj = args[0].As(); bool parsedSuccessfully = parseCommonParameters(obj, params); if (!parsedSuccessfully) @@ -1476,37 +1457,36 @@ argumentsToTripParameter(const Nan::FunctionCallbackInfo &args, return trip_parameters_ptr(); } - if (Nan::Has(obj, Nan::New("roundtrip").ToLocalChecked()).FromJust()) + if (obj.Has("roundtrip")) { - auto roundtrip = Nan::Get(obj, Nan::New("roundtrip").ToLocalChecked()).ToLocalChecked(); + auto roundtrip = obj.Get("roundtrip"); if (roundtrip.IsEmpty()) return trip_parameters_ptr(); - if (roundtrip->IsBoolean()) + if (roundtrip.IsBoolean()) { - params->roundtrip = Nan::To(roundtrip).FromJust(); + params->roundtrip = roundtrip.ToBoolean().Value(); } else { - Nan::ThrowError("'roundtrip' param must be a boolean"); + ThrowError(args.Env(), "'roundtrip' param must be a boolean"); return trip_parameters_ptr(); } } - if (Nan::Has(obj, Nan::New("source").ToLocalChecked()).FromJust()) + if (obj.Has("source")) { - v8::Local source = - Nan::Get(obj, Nan::New("source").ToLocalChecked()).ToLocalChecked(); + Napi::Value source = obj.Get("source"); if (source.IsEmpty()) return trip_parameters_ptr(); - if (!source->IsString()) + if (!source.IsString()) { - Nan::ThrowError("Source must be a string: [any, first]"); + ThrowError(args.Env(), "Source must be a string: [any, first]"); return trip_parameters_ptr(); } - std::string source_str = *Nan::Utf8String(source); + std::string source_str = source.ToString().Utf8Value(); if (source_str == "first") { @@ -1518,25 +1498,24 @@ argumentsToTripParameter(const Nan::FunctionCallbackInfo &args, } else { - Nan::ThrowError("'source' param must be one of [any, first]"); + ThrowError(args.Env(), "'source' param must be one of [any, first]"); return trip_parameters_ptr(); } } - if (Nan::Has(obj, Nan::New("destination").ToLocalChecked()).FromJust()) + if (obj.Has("destination")) { - v8::Local destination = - Nan::Get(obj, Nan::New("destination").ToLocalChecked()).ToLocalChecked(); + Napi::Value destination = obj.Get("destination"); if (destination.IsEmpty()) return trip_parameters_ptr(); - if (!destination->IsString()) + if (!destination.IsString()) { - Nan::ThrowError("Destination must be a string: [any, last]"); + ThrowError(args.Env(), "Destination must be a string: [any, last]"); return trip_parameters_ptr(); } - std::string destination_str = *Nan::Utf8String(destination); + std::string destination_str = destination.ToString().Utf8Value(); if (destination_str == "last") { @@ -1548,7 +1527,7 @@ argumentsToTripParameter(const Nan::FunctionCallbackInfo &args, } else { - Nan::ThrowError("'destination' param must be one of [any, last]"); + ThrowError(args.Env(), "'destination' param must be one of [any, last]"); return trip_parameters_ptr(); } } @@ -1556,69 +1535,66 @@ argumentsToTripParameter(const Nan::FunctionCallbackInfo &args, return params; } -inline match_parameters_ptr -argumentsToMatchParameter(const Nan::FunctionCallbackInfo &args, - bool requires_multiple_coordinates) +inline match_parameters_ptr argumentsToMatchParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) { match_parameters_ptr params = std::make_unique(); bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); if (!has_base_params) return match_parameters_ptr(); - v8::Local obj = Nan::To(args[0]).ToLocalChecked(); + Napi::Object obj = args[0].As(); - if (Nan::Has(obj, Nan::New("timestamps").ToLocalChecked()).FromJust()) + if (obj.Has("timestamps")) { - v8::Local timestamps = - Nan::Get(obj, Nan::New("timestamps").ToLocalChecked()).ToLocalChecked(); + Napi::Value timestamps = obj.Get("timestamps"); if (timestamps.IsEmpty()) return match_parameters_ptr(); - if (!timestamps->IsArray()) + if (!timestamps.IsArray()) { - Nan::ThrowError("Timestamps must be an array of integers (or undefined)"); + ThrowError(args.Env(), "Timestamps must be an array of integers (or undefined)"); return match_parameters_ptr(); } - v8::Local timestamps_array = v8::Local::Cast(timestamps); + Napi::Array timestamps_array = timestamps.As(); - if (params->coordinates.size() != timestamps_array->Length()) + if (params->coordinates.size() != timestamps_array.Length()) { - Nan::ThrowError("Timestamp array must have the same size as the coordinates " - "array"); + ThrowError(args.Env(), + "Timestamp array must have the same size as the coordinates " + "array"); return match_parameters_ptr(); } - for (uint32_t i = 0; i < timestamps_array->Length(); ++i) + for (uint32_t i = 0; i < timestamps_array.Length(); ++i) { - v8::Local timestamp = Nan::Get(timestamps_array, i).ToLocalChecked(); + Napi::Value timestamp = timestamps_array.Get(i); if (timestamp.IsEmpty()) return match_parameters_ptr(); - if (!timestamp->IsNumber()) + if (!timestamp.IsNumber()) { - Nan::ThrowError("Timestamps array items must be numbers"); + ThrowError(args.Env(), "Timestamps array items must be numbers"); return match_parameters_ptr(); } - params->timestamps.emplace_back(Nan::To(timestamp).FromJust()); + params->timestamps.emplace_back(timestamp.ToNumber().Int64Value()); } } - if (Nan::Has(obj, Nan::New("gaps").ToLocalChecked()).FromJust()) + if (obj.Has("gaps")) { - v8::Local gaps = - Nan::Get(obj, Nan::New("gaps").ToLocalChecked()).ToLocalChecked(); + Napi::Value gaps = obj.Get("gaps"); if (gaps.IsEmpty()) return match_parameters_ptr(); - if (!gaps->IsString()) + if (!gaps.IsString()) { - Nan::ThrowError("Gaps must be a string: [split, ignore]"); + ThrowError(args.Env(), "Gaps must be a string: [split, ignore]"); return match_parameters_ptr(); } - const Nan::Utf8String gaps_utf8str(gaps); - std::string gaps_str{*gaps_utf8str, *gaps_utf8str + gaps_utf8str.length()}; + std::string gaps_str = gaps.ToString().Utf8Value(); if (gaps_str == "split") { @@ -1630,83 +1606,81 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo &args, } else { - Nan::ThrowError("'gaps' param must be one of [split, ignore]"); + ThrowError(args.Env(), "'gaps' param must be one of [split, ignore]"); return match_parameters_ptr(); } } - if (Nan::Has(obj, Nan::New("tidy").ToLocalChecked()).FromJust()) + if (obj.Has("tidy")) { - v8::Local tidy = - Nan::Get(obj, Nan::New("tidy").ToLocalChecked()).ToLocalChecked(); + Napi::Value tidy = obj.Get("tidy"); if (tidy.IsEmpty()) return match_parameters_ptr(); - if (!tidy->IsBoolean()) + if (!tidy.IsBoolean()) { - Nan::ThrowError("tidy must be of type Boolean"); + ThrowError(args.Env(), "tidy must be of type Boolean"); return match_parameters_ptr(); } - params->tidy = Nan::To(tidy).FromJust(); + params->tidy = tidy.ToBoolean().Value(); } - if (Nan::Has(obj, Nan::New("waypoints").ToLocalChecked()).FromJust()) + if (obj.Has("waypoints")) { - v8::Local waypoints = - Nan::Get(obj, Nan::New("waypoints").ToLocalChecked()).ToLocalChecked(); + Napi::Value waypoints = obj.Get("waypoints"); if (waypoints.IsEmpty()) return match_parameters_ptr(); // must be array - if (!waypoints->IsArray()) + if (!waypoints.IsArray()) { - Nan::ThrowError( + ThrowError( + args.Env(), "Waypoints must be an array of integers corresponding to the input coordinates."); return match_parameters_ptr(); } - auto waypoints_array = v8::Local::Cast(waypoints); + auto waypoints_array = waypoints.As(); // must have at least two elements - if (waypoints_array->Length() < 2) + if (waypoints_array.Length() < 2) { - Nan::ThrowError("At least two waypoints must be provided"); + ThrowError(args.Env(), "At least two waypoints must be provided"); return match_parameters_ptr(); } auto coords_size = params->coordinates.size(); - auto waypoints_array_size = waypoints_array->Length(); + auto waypoints_array_size = waypoints_array.Length(); const auto first_index = - Nan::To(Nan::Get(waypoints_array, 0).ToLocalChecked()).FromJust(); + waypoints_array.Get(static_cast(0)).ToNumber().Uint32Value(); const auto last_index = - Nan::To( - Nan::Get(waypoints_array, waypoints_array_size - 1).ToLocalChecked()) - .FromJust(); + waypoints_array.Get(waypoints_array_size - 1).ToNumber().Uint32Value(); if (first_index != 0 || last_index != coords_size - 1) { - Nan::ThrowError("First and last waypoints values must correspond to first and last " - "coordinate indices"); + ThrowError(args.Env(), + "First and last waypoints values must correspond to first and last " + "coordinate indices"); return match_parameters_ptr(); } for (uint32_t i = 0; i < waypoints_array_size; ++i) { - v8::Local waypoint_value = Nan::Get(waypoints_array, i).ToLocalChecked(); + Napi::Value waypoint_value = waypoints_array.Get(i); // all elements must be numbers - if (!waypoint_value->IsNumber()) + if (!waypoint_value.IsNumber()) { - Nan::ThrowError("Waypoint values must be an array of integers"); + ThrowError(args.Env(), "Waypoint values must be an array of integers"); return match_parameters_ptr(); } // check that the waypoint index corresponds with an inpute coordinate - const auto index = Nan::To(waypoint_value).FromJust(); + const auto index = waypoint_value.ToNumber().Uint32Value(); if (index >= coords_size) { - Nan::ThrowError("Waypoints must correspond with the index of an input coordinate"); + ThrowError(args.Env(), + "Waypoints must correspond with the index of an input coordinate"); return match_parameters_ptr(); } - params->waypoints.emplace_back( - static_cast(Nan::To(waypoint_value).FromJust())); + params->waypoints.emplace_back(index); } } diff --git a/lib/binding_napi_v8 b/lib/binding_napi_v8 new file mode 120000 index 000000000..32bc84fb7 --- /dev/null +++ b/lib/binding_napi_v8 @@ -0,0 +1 @@ +binding \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2136845ed..457213005 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "faucet": "^0.0.1", "jsonpath": "^1.1.1", "mkdirp": "^0.5.6", - "nan": "^2.17.0", + "node-addon-api": "^5.0.0", "node-cmake": "^2.5.1", "node-timeout": "0.0.4", "polyline": "^0.2.0", @@ -5436,9 +5436,9 @@ } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "node_modules/color-string": { @@ -6011,6 +6011,15 @@ "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=", "dev": true }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -9114,7 +9123,7 @@ "node_modules/find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "dependencies": { "path-exists": "^2.0.0", @@ -10038,13 +10047,10 @@ "dev": true }, "node_modules/graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true }, "node_modules/gulp-sourcemaps": { "version": "1.6.0", @@ -11854,7 +11860,7 @@ "node_modules/load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", "dev": true, "dependencies": { "graceful-fs": "^4.1.2", @@ -12711,6 +12717,12 @@ "lower-case": "^1.1.1" } }, + "node_modules/node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==", + "dev": true + }, "node_modules/node-cmake": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/node-cmake/-/node-cmake-2.5.1.tgz", @@ -13481,7 +13493,7 @@ "node_modules/path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", "dev": true, "dependencies": { "graceful-fs": "^4.1.2", @@ -13536,7 +13548,7 @@ "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, "engines": { "node": ">=0.10.0" @@ -14276,7 +14288,7 @@ "node_modules/read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "dependencies": { "load-json-file": "^1.0.0", @@ -14290,7 +14302,7 @@ "node_modules/read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "dependencies": { "find-up": "^1.0.0", @@ -15126,9 +15138,9 @@ } }, "node_modules/signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/simple-concat": { "version": "1.0.1", @@ -16644,15 +16656,6 @@ "node": ">=4.0.0" } }, - "node_modules/table-layout/node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/table/node_modules/ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", @@ -18846,9 +18849,9 @@ "dev": true }, "node_modules/yargs": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz", - "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", + "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", "dev": true, "dependencies": { "camelcase": "^3.0.0", @@ -18863,13 +18866,13 @@ "string-width": "^1.0.2", "which-module": "^1.0.0", "y18n": "^3.2.1", - "yargs-parser": "5.0.0-security.0" + "yargs-parser": "^5.0.1" } }, "node_modules/yargs-parser": { - "version": "5.0.0-security.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz", - "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", + "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", "dev": true, "dependencies": { "camelcase": "^3.0.0", @@ -23193,9 +23196,9 @@ } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "color-string": { @@ -23690,6 +23693,12 @@ "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=", "dev": true }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -26233,7 +26242,7 @@ "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "requires": { "path-exists": "^2.0.0", @@ -26966,9 +26975,9 @@ "dev": true }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "gulp-sourcemaps": { @@ -28353,7 +28362,7 @@ "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -29082,6 +29091,12 @@ "lower-case": "^1.1.1" } }, + "node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==", + "dev": true + }, "node-cmake": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/node-cmake/-/node-cmake-2.5.1.tgz", @@ -29696,7 +29711,7 @@ "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -29739,7 +29754,7 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true }, "pinkie": { @@ -30383,7 +30398,7 @@ "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "requires": { "load-json-file": "^1.0.0", @@ -30394,7 +30409,7 @@ "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "requires": { "find-up": "^1.0.0", @@ -31099,9 +31114,9 @@ } }, "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "simple-concat": { "version": "1.0.1", @@ -32325,14 +32340,6 @@ "lodash.padend": "^4.6.1", "typical": "^2.6.1", "wordwrapjs": "^3.0.0" - }, - "dependencies": { - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - } } }, "tap-parser": { @@ -34121,9 +34128,9 @@ "dev": true }, "yargs": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz", - "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", + "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", "dev": true, "requires": { "camelcase": "^3.0.0", @@ -34138,13 +34145,13 @@ "string-width": "^1.0.2", "which-module": "^1.0.0", "y18n": "^3.2.1", - "yargs-parser": "5.0.0-security.0" + "yargs-parser": "^5.0.1" } }, "yargs-parser": { - "version": "5.0.0-security.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz", - "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", + "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", "dev": true, "requires": { "camelcase": "^3.0.0", diff --git a/package.json b/package.json index 9124e8989..6e464a71a 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "babelify": "^10.0.0", "browserify": "^17.0.0", "chalk": "^1.1.3", + "cheap-ruler": "^3.0.2", "command-line-args": "^5.2.1", "command-line-usage": "^5.0.4", "csv-stringify": "^3.0.0", @@ -55,26 +56,26 @@ "eslint": "^5.16.0", "faucet": "^0.0.1", "jsonpath": "^1.1.1", + "mkdirp": "^0.5.6", + "node-addon-api": "^5.0.0", "node-timeout": "0.0.4", "polyline": "^0.2.0", "request": "^2.88.2", + "rimraf": "^2.7.1", "tape": "^4.16.0", "turf": "^3.0.14", "uglify-js": "^3.17.0", "xmlbuilder": "^4.2.1", - "cheap-ruler": "^3.0.2", - "mkdirp": "^0.5.6", - "nan": "^2.17.0", - "node-cmake": "^2.5.1", - "rimraf": "^2.7.1" + "node-cmake": "^2.5.1" }, "main": "lib/index.js", "binary": { + "napi_versions": [8], "module_name": "node_osrm", - "module_path": "./lib/binding/", + "module_path": "./lib/binding_napi_v{napi_build_version}/", "host": "https://github.com", "remote_path": "./Project-OSRM/osrm-backend/releases/download/v{version}/", - "package_name": "{module_name}-v{version}-{node_abi}-{platform}-{arch}-{configuration}.tar.gz" + "package_name": "{module_name}-v{version}-{napi_build_version}-{platform}-{arch}-{configuration}.tar.gz" }, "publishConfig": { "access": "public" diff --git a/src/nodejs/CMakeLists.txt b/src/nodejs/CMakeLists.txt index 7d93a09b6..85ee29ecf 100644 --- a/src/nodejs/CMakeLists.txt +++ b/src/nodejs/CMakeLists.txt @@ -4,6 +4,9 @@ cmake_minimum_required(VERSION 3.1) message(STATUS "Building node_osrm") +set(NAPI_VERSION 8) +add_definitions(-DNAPI_VERSION=${NAPI_VERSION}) + set(BINDING_DIR "${PROJECT_SOURCE_DIR}/lib/binding") list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/node_modules/node-cmake") @@ -13,6 +16,7 @@ nodejs_init() message(STATUS "Configuring node_osrm bindings for NodeJs ${NODEJS_VERSION}") + add_nodejs_module(node_osrm node_osrm.cpp) set_target_properties(node_osrm PROPERTIES CXX_STANDARD 17) # TODO: we disable clang-tidy for this target, because it causes errors in third-party NodeJs related headers @@ -21,6 +25,14 @@ set_target_properties(node_osrm PROPERTIES CXX_CLANG_TIDY "") target_no_warning(node_osrm suggest-destructor-override) target_no_warning(node_osrm suggest-override) +# https://github.com/cjntaylor/node-cmake/issues/53#issuecomment-842357457 +execute_process(COMMAND node -p "require('node-addon-api').include" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE NODE_ADDON_API_DIR) +string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR}) +string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR}) + +target_include_directories(node_osrm SYSTEM PRIVATE ${NODE_ADDON_API_DIR}) + + target_link_libraries(node_osrm osrm) # node_osrm artifacts in ${BINDING_DIR} to depend targets on diff --git a/src/nodejs/node_osrm.cpp b/src/nodejs/node_osrm.cpp index 34ecc6914..6471b7697 100644 --- a/src/nodejs/node_osrm.cpp +++ b/src/nodejs/node_osrm.cpp @@ -1,3 +1,5 @@ + + #include "osrm/engine_config.hpp" #include "osrm/osrm.hpp" @@ -9,6 +11,7 @@ #include "osrm/trip_parameters.hpp" #include +#include #include #include #include @@ -21,35 +24,25 @@ namespace node_osrm { - -Engine::Engine(osrm::EngineConfig &config) : Base(), this_(std::make_shared(config)) {} - -Nan::Persistent &Engine::constructor() +Napi::Object Engine::Init(Napi::Env env, Napi::Object exports) { - static Nan::Persistent init; - return init; -} + Napi::Function func = DefineClass(env, + "OSRM", + { + InstanceMethod("route", &Engine::route), + InstanceMethod("nearest", &Engine::nearest), + InstanceMethod("table", &Engine::table), + InstanceMethod("tile", &Engine::tile), + InstanceMethod("match", &Engine::match), + InstanceMethod("trip", &Engine::trip), + }); -NAN_MODULE_INIT(Engine::Init) -{ - const auto whoami = Nan::New("OSRM").ToLocalChecked(); + Napi::FunctionReference *constructor = new Napi::FunctionReference(); + *constructor = Napi::Persistent(func); + env.SetInstanceData(constructor); - auto fnTp = Nan::New(New); - fnTp->InstanceTemplate()->SetInternalFieldCount(1); - fnTp->SetClassName(whoami); - - SetPrototypeMethod(fnTp, "route", route); - SetPrototypeMethod(fnTp, "nearest", nearest); - SetPrototypeMethod(fnTp, "table", table); - SetPrototypeMethod(fnTp, "tile", tile); - SetPrototypeMethod(fnTp, "match", match); - SetPrototypeMethod(fnTp, "trip", trip); - - const auto fn = Nan::GetFunction(fnTp).ToLocalChecked(); - - constructor().Reset(fn); - - Nan::Set(target, whoami, fn); + exports.Set("OSRM", func); + return exports; } // clang-format off @@ -93,35 +86,25 @@ NAN_MODULE_INIT(Engine::Init) * */ // clang-format on -NAN_METHOD(Engine::New) +Engine::Engine(const Napi::CallbackInfo &info) : Napi::ObjectWrap(info) { - if (info.IsConstructCall()) + + try { - try - { - auto config = argumentsToEngineConfig(info); - if (!config) - return; + auto config = argumentsToEngineConfig(info); + if (!config) + return; - auto *const self = new Engine(*config); - self->Wrap(info.This()); - } - catch (const std::exception &ex) - { - return Nan::ThrowTypeError(ex.what()); - } - - info.GetReturnValue().Set(info.This()); + this_ = std::make_shared(*config); } - else + catch (const std::exception &ex) { - return Nan::ThrowTypeError( - "Cannot call constructor as function, you need to use 'new' keyword"); + ThrowTypeError(info.Env(), ex.what()); } } template -inline void async(const Nan::FunctionCallbackInfo &info, +inline void async(const Napi::CallbackInfo &info, ParameterParser argsToParams, ServiceMemFn service, bool requires_multiple_coordinates) @@ -133,22 +116,21 @@ inline void async(const Nan::FunctionCallbackInfo &info, BOOST_ASSERT(params->IsValid()); - if (!info[info.Length() - 1]->IsFunction()) - return Nan::ThrowTypeError("last argument must be a callback function"); + if (!info[info.Length() - 1].IsFunction()) + return ThrowTypeError(info.Env(), "last argument must be a callback function"); - auto *const self = Nan::ObjectWrap::Unwrap(info.Holder()); + auto *const self = Napi::ObjectWrap::Unwrap(info.This().As()); using ParamPtr = decltype(params); - struct Worker final : Nan::AsyncWorker + struct Worker final : Napi::AsyncWorker { Worker(std::shared_ptr osrm_, ParamPtr params_, ServiceMemFn service, - Nan::Callback *callback, + Napi::Function callback, PluginParameters pluginParams_) - : Nan::AsyncWorker(callback, "osrm:async"), osrm{std::move(osrm_)}, - service{std::move(service)}, params{std::move(params_)}, pluginParams{ - std::move(pluginParams_)} + : Napi::AsyncWorker(callback), osrm{std::move(osrm_)}, service{std::move(service)}, + params{std::move(params_)}, pluginParams{std::move(pluginParams_)} { } @@ -194,17 +176,14 @@ inline void async(const Nan::FunctionCallbackInfo &info, } catch (const std::exception &e) { - SetErrorMessage(e.what()); + SetError(e.what()); } - void HandleOKCallback() override + void OnOK() override { - Nan::HandleScope scope; + Napi::HandleScope scope{Env()}; - const constexpr auto argc = 2u; - v8::Local argv[argc] = {Nan::Null(), render(result)}; - - callback->Call(argc, argv, async_resource); + Callback().Call({Env().Null(), render(Env(), result)}); } // Keeps the OSRM object alive even after shutdown until we're done with callback @@ -216,13 +195,14 @@ inline void async(const Nan::FunctionCallbackInfo &info, ObjectOrString result; }; - auto *callback = new Nan::Callback{info[info.Length() - 1].As()}; - Nan::AsyncQueueWorker( - new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)}); + Napi::Function callback = info[info.Length() - 1].As(); + auto worker = + new Worker(self->this_, std::move(params), service, callback, std::move(pluginParams)); + worker->Queue(); } template -inline void asyncForTiles(const Nan::FunctionCallbackInfo &info, +inline void asyncForTiles(const Napi::CallbackInfo &info, ParameterParser argsToParams, ServiceMemFn service, bool requires_multiple_coordinates) @@ -235,22 +215,21 @@ inline void asyncForTiles(const Nan::FunctionCallbackInfo &info, BOOST_ASSERT(params->IsValid()); - if (!info[info.Length() - 1]->IsFunction()) - return Nan::ThrowTypeError("last argument must be a callback function"); + if (!info[info.Length() - 1].IsFunction()) + return ThrowTypeError(info.Env(), "last argument must be a callback function"); - auto *const self = Nan::ObjectWrap::Unwrap(info.Holder()); + auto *const self = Napi::ObjectWrap::Unwrap(info.This().As()); using ParamPtr = decltype(params); - struct Worker final : Nan::AsyncWorker + struct Worker final : Napi::AsyncWorker { Worker(std::shared_ptr osrm_, ParamPtr params_, ServiceMemFn service, - Nan::Callback *callback, + Napi::Function callback, PluginParameters pluginParams_) - : Nan::AsyncWorker(callback, "osrm:asyncForTiles"), osrm{std::move(osrm_)}, - service{std::move(service)}, params{std::move(params_)}, pluginParams{ - std::move(pluginParams_)} + : Napi::AsyncWorker(callback), osrm{std::move(osrm_)}, service{std::move(service)}, + params{std::move(params_)}, pluginParams{std::move(pluginParams_)} { } @@ -264,18 +243,14 @@ inline void asyncForTiles(const Nan::FunctionCallbackInfo &info, } catch (const std::exception &e) { - SetErrorMessage(e.what()); + SetError(e.what()); } - void HandleOKCallback() override + void OnOK() override { - Nan::HandleScope scope; + Napi::HandleScope scope{Env()}; - const constexpr auto argc = 2u; - auto str_result = result.get(); - v8::Local argv[argc] = {Nan::Null(), render(str_result)}; - - callback->Call(argc, argv, async_resource); + Callback().Call({Env().Null(), render(Env(), result.get())}); } // Keeps the OSRM object alive even after shutdown until we're done with callback @@ -287,9 +262,10 @@ inline void asyncForTiles(const Nan::FunctionCallbackInfo &info, osrm::engine::api::ResultT result; }; - auto *callback = new Nan::Callback{info[info.Length() - 1].As()}; - Nan::AsyncQueueWorker( - new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)}); + Napi::Function callback = info[info.Length() - 1].As(); + auto worker = + new Worker(self->this_, std::move(params), service, callback, std::move(pluginParams)); + worker->Queue(); } // clang-format off @@ -333,12 +309,13 @@ inline void asyncForTiles(const Nan::FunctionCallbackInfo &info, * }); */ // clang-format on -NAN_METHOD(Engine::route) // +Napi::Value Engine::route(const Napi::CallbackInfo &info) { osrm::Status (osrm::OSRM::*route_fn)(const osrm::RouteParameters ¶ms, osrm::engine::api::ResultT &result) const = &osrm::OSRM::Route; async(info, &argumentsToRouteParameter, route_fn, true); + return info.Env().Undefined(); } // clang-format off @@ -379,12 +356,13 @@ NAN_METHOD(Engine::route) // * }); */ // clang-format on -NAN_METHOD(Engine::nearest) // +Napi::Value Engine::nearest(const Napi::CallbackInfo &info) { osrm::Status (osrm::OSRM::*nearest_fn)(const osrm::NearestParameters ¶ms, osrm::engine::api::ResultT &result) const = &osrm::OSRM::Nearest; async(info, &argumentsToNearestParameter, nearest_fn, false); + return info.Env().Undefined(); } // clang-format off @@ -410,7 +388,6 @@ NAN_METHOD(Engine::nearest) // * @param {Number} [options.scale_factor] Multiply the table duration values in the table by this number for more controlled input into a route optimization solver. * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. * @param {Array} [options.annotations] Return the requested table or tables in response. Can be `['duration']` (return the duration matrix, default), `[distance']` (return the distance matrix), or `['duration', distance']` (return both the duration matrix and the distance matrix). - * @param {Function} callback * * @returns {Object} containing `durations`, `distances`, `sources`, and `destinations`. @@ -439,12 +416,13 @@ NAN_METHOD(Engine::nearest) // * }); */ // clang-format on -NAN_METHOD(Engine::table) // +Napi::Value Engine::table(const Napi::CallbackInfo &info) { osrm::Status (osrm::OSRM::*table_fn)(const osrm::TableParameters ¶ms, osrm::engine::api::ResultT &result) const = &osrm::OSRM::Table; async(info, &argumentsToTableParameter, table_fn, true); + return info.Env().Undefined(); } // clang-format off @@ -473,12 +451,13 @@ NAN_METHOD(Engine::table) // * }); */ // clang-format on -NAN_METHOD(Engine::tile) +Napi::Value Engine::tile(const Napi::CallbackInfo &info) { osrm::Status (osrm::OSRM::*tile_fn)(const osrm::TileParameters ¶ms, osrm::engine::api::ResultT &result) const = &osrm::OSRM::Tile; asyncForTiles(info, &argumentsToTileParameters, tile_fn, {/*unused*/}); + return info.Env().Undefined(); } // clang-format off @@ -536,12 +515,13 @@ NAN_METHOD(Engine::tile) * */ // clang-format on -NAN_METHOD(Engine::match) // +Napi::Value Engine::match(const Napi::CallbackInfo &info) { osrm::Status (osrm::OSRM::*match_fn)(const osrm::MatchParameters ¶ms, osrm::engine::api::ResultT &result) const = &osrm::OSRM::Match; async(info, &argumentsToMatchParameter, match_fn, true); + return info.Env().Undefined(); } // clang-format off @@ -611,12 +591,13 @@ NAN_METHOD(Engine::match) // * }); */ // clang-format on -NAN_METHOD(Engine::trip) // +Napi::Value Engine::trip(const Napi::CallbackInfo &info) { osrm::Status (osrm::OSRM::*trip_fn)(const osrm::TripParameters ¶ms, osrm::engine::api::ResultT &result) const = &osrm::OSRM::Trip; async(info, &argumentsToTripParameter, trip_fn, true); + return info.Env().Undefined(); } /** @@ -710,3 +691,10 @@ NAN_METHOD(Engine::trip) // */ } // namespace node_osrm + +Napi::Object InitAll(Napi::Env env, Napi::Object exports) +{ + return node_osrm::Engine::Init(env, exports); +} + +NODE_API_MODULE(addon, InitAll) diff --git a/test/nodejs/benchmark.js b/test/nodejs/benchmark.js new file mode 100644 index 000000000..e8912d606 --- /dev/null +++ b/test/nodejs/benchmark.js @@ -0,0 +1,51 @@ +const OSRM = require('../../'); +const {performance, createHistogram} = require('node:perf_hooks'); + +// usage: node test/nodejs/benchmark.js berlin-latest.osrm 13.388860,52.517037;13.385983,52.496891 +const args = process.argv.slice(2); +const path = args[0] || require('./constants').mld_data_path; + +function parseWaypoints(waypoints) { + if (waypoints == undefined) { + return undefined; + } + return waypoints.split(';').map((waypoint) => { + const [lon, lat] = waypoint.split(','); + return [parseFloat(lon), parseFloat(lat)]; + }); +} +const waypoints = parseWaypoints(args[1]) || [[7.41337, 43.72956],[7.41546, 43.73077]]; +const osrm = new OSRM({path, algorithm: 'MLD'}); + +async function route(coordinates) { + const promise = new Promise((resolve, reject) => { + osrm.route({coordinates, steps: true, overview: 'full'}, (err, result) => { + if (err) { + reject(err); + } else { + resolve(result); + } + }); + }); + return promise; +} + +async function benchmark() { + // warmup + await route(waypoints); + + const performanceHistorgram = createHistogram(); + + for (let i = 0; i < 1000; i++) { + const start = performance.now(); + await route(waypoints); + const end = performance.now(); + // record result in microseconds + performanceHistorgram.record(Math.ceil((end - start) * 1000)); + } + + + console.log(performanceHistorgram); +} +benchmark(); + diff --git a/test/nodejs/index.js b/test/nodejs/index.js index bbe58849f..f08356706 100644 --- a/test/nodejs/index.js +++ b/test/nodejs/index.js @@ -8,7 +8,7 @@ var monaco_corech_path = require('./constants').corech_data_path; test('constructor: throws if new keyword is not used', function(assert) { assert.plan(1); assert.throws(function() { OSRM(); }, - /Cannot call constructor as function, you need to use 'new' keyword/); + /Class constructors cannot be invoked without 'new'/); }); test('constructor: uses defaults with no parameter', function(assert) {